Каналы Redux Saga Firebase - PullRequest
       18

Каналы Redux Saga Firebase

0 голосов
/ 30 октября 2019

Я создаю собственное приложение с Redux Saga Firebase и не могу понять, как использовать firestore.channel () и отображать новые данные в пользовательскую ленту компонента. У меня есть пример кода для моих действий примитива, редукторов, саг и компонента ниже.

Каков наилучший способ создания канала для автоматического отображения пользователями новых данных в компоненте UserFeed?

Ссылки на документацию:

Что я пытаюсь создать: - Я создаю приложение, в котором пользователи могут видеть всех пользователей в Cloud Firestore, поэтому у меня есть коллекция / users в Cloudfirestore. На данный момент есть только два поля: полное_имя и созданная_дата - когда кто-то в приложении вводит полное имя в текстовом поле и нажимает кнопку, я хочу, чтобы каждый пользователь в приложении автоматически получал нового пользователя в фиде своих пользователей. Это должно вернуть только новый документ, а не всю коллекцию, так что

Redux Actions:

// Add User Request
export const addUserRequest = (state) => ({
  type: 'ADD_USER_REQUEST',
  userName: state.userName,
});

// Add User Success
export const addUserSuccess = () => ({
  type: 'ADD_USER_SUCCESS',
});

// Add User Error
export const addUserError = (error) => ({
  type: 'ADD_USER_ERROR',
  firebaseError: error,
});

// Users Channel Request
export const usersChannelRequest = () => ({
  type: 'USERS_CHANNEL_REQUEST',
});

// Users Channel Success
export const usersChannelSuccess = (data) => ({
  type: 'USERS_CHANNEL_SUCCESS',
  usersChannel: data,
});

// Users Channel Error
export const usersChannelError = (error) => ({
  type: 'USERS_CHANNEL_ERROR',
  firebaseError: error,
});

Redux Reducers:

// Initial state
const initialState = {
    loading: false,
    firebaseError: null,
    usersChannel: [],
  };

  // Feed Reducer
  export default function feedReducer (state = initialState, action) {
    switch (action.type) {
      // Add User
      case 'ADD_USER_REQUEST':
        return {
          ...state,
          loading: true,
          userName: action.userName,
        }

      // Add User Success
      case 'ADD_USER_SUCCESS':
        return {
          ...state,
          loading: false,
        }

      // Add User Error
      case 'ADD_USER_ERROR':
        return {
          ...state,
          loading: false,
          firebaseError: action.firebaseError,
        }

      // Users Channel Collection
      case 'USERS_CHANNEL_COLLECTION_REQUEST':
        return {
          ...state,
          loading: true,
        }

      // Users Channel Collection Success
      case 'USERS_CHANNEL_COLLECTION_SUCCESS':
        return {
          ...state,
          loading: false,
          usersChannel: action.usersChannel,
        }

      // Users Channel Collection Error
      case 'USERS_CHANNEL_COLLECTION_ERROR':
        return {
          ...state,
          loading: false,
          firebaseError: action.firebaseError,
        }

      // Default
      default:
        return state;
    }
  }

Redux Sagas:

// Imports: Dependencies
import { all, call, delay, fork, put, take, takeEvery, takeLatest } from 'redux-saga/effects';
import reduxSagaFirebase from '../../firebase/firebase';

// Imports: Redux Actions
import {
  // Add User
  addUserSuccess,
  addUserError,
  // Users Channel (Gets New Document Updates)
  usersChannelSuccess,
  usersChannelError,
} from '../actions/feedActions';

// Imports: Firestore References
import { usersRef } from '../../firebase/firebase';

// Redux Saga: Add User
function* addUserSaga(action) {
  try {
    // Redux Saga Firebase: New Document (Add Document Will Automatically Generate A Document ID)
    yield call(reduxSagaFirebase.firestore.addDocument, usersRef, {
      user_name: action.userName,
      created_at: new Date(),
    });

    // Add User Success
    yield put(addUserSuccess());
  }
  catch (error) {
    // Add User Error
    alert(`${error}`);
    yield put(addUserError(error));
  }
};

// Redux Saga: Users Channel (Recieves Document Updates When A Change Is Made In Cloud Firestore)
function* usersChannelSaga () {
  // Firestore: Channel
  const channel = eventChannel(emit => usersRef.onSnapshot(emit))

  try {
    while (true) {
      const data = yield take(channel);
      yield put(usersChannelSuccess(data));
    }
  }
  catch (error) {
    yield put(usersChannelError(error));
  }
}

// Watcher: Add User
export function* watchaddUserSaga() {
  yield takeLatest('ADD_USER_REQUEST', addUserSaga);
};

// Watcher: Users Channel
export function* watchUsersChannelSaga() {
  yield takeLatest('USERS_CHANNEL_REQUEST', usersChannelSaga);

Добавление пользователей / компонента фида:

// Imports: Dependencies
import React from 'react';
import { Dimensions, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { connect } from 'react-redux';
import Icon from 'react-native-vector-icons/Ionicons';
Icon.loadFont();

// Imports: Redux Actions
import {
  addUserRequest,
  usersChannelRequest,
} from '../redux/actions/feedActions';

// Screen Dimensions
const { height, width } = Dimensions.get('window');

// Screen: UserFeed
class UserFeed extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      userName: null,
      users: [],
    };
  }

  // Add User
  addUser = () => {
    try {
      // Redux: Add User Request
      this.props.reduxAddUserRequest(this.state);

      // Set State
      this.setState({
        userName: null,
      })
    }
    catch (error) {
      console.log(error);
    }
  };

  // Render Users
  renderUsers = () => {
    try {

      // Users Channel
      let data = this.props.reduxUsersChannelRequest();
      console.log('Users Channel');
      console.log(this.props.usersChannel);

      // Map Users
      return data.map((item, i) => (
        <TouchableOpacity
          key={i}
          onPress={() => this.addUser(item)}
        >
          <Text>{item.firstName}</Text>
          </TouchableOpacity>
        ))
    }
    catch (error) {
      console.log(error);
    }
  };

  render() {
    return (
      <SafeAreaView style={styles.container}>
        <View style={styles.scheduleTitleContainer}>
          <Text></Text>
          <TouchableOpacity onPress={this.addUser}>
            <Icon name="ios-add-circle" color={'#007AFF'} size={42} style={styles.addCircle}/>
          </TouchableOpacity>
        </View>

        <View>
          <TextInput 
            style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
            onChangeText={text => this.setState({userName: text})}
            value={this.state.userName}
          />
        </View>

        <ScrollView style={styles.scrollView}>
          {this.renderUsers()}
        </ScrollView>
      </SafeAreaView>
    )
  }
}

// Styles
const styles = StyleSheet.create({
  container: {
    display: 'flex',
    height: '100%',
    width: width - 32,
    marginLeft: 16,
    marginRight: 16,
  },
  scheduleTitleContainer: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  addCircle: {
    marginTop: 45,
    marginBottom: 12,
  },
  scrollView: {
    height: 'auto',
  },
  text: {
    fontFamily: 'System',
    fontSize: 16,
    fontWeight: '400',
    color: '#000000',
  },
});

// Map State To Props (Redux Store --> Component)
const mapStateToProps = (state) => {
  // Redux Store --> Component
  return {
    // Users Channel
    usersChannel: state.feedReducer.usersChannel,
  };
};


// Map Dispatch To Props (Dispatch Actions To Redux Store To Grab Data)
const mapDispatchToProps = (dispatch) => {
    // Action
    return {
      // Add User
      reduxAddUserRequest: (state) => dispatch(addUserRequest(state)),
      // Users Channel
      reduxUsersChannelRequest: () => dispatch(usersChannelRequest()),
    };
  };

// Exports
export default connect(mapStateToProps, mapDispatchToProps)(Feed);
...