Я создаю собственное приложение с 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);