Мне не удалось решить проблему, связанную с бесконечными циклами с использованием React Hooks и Redux в useEffect. Я прочитал много статей об useEffect (https://overreacted.io/a-complete-guide-to-useeffect/, https://reactjs.org/docs/hooks-faq.html#is -it-safe-to-omit-functions-from-the-list-of-dependencies , https://www.robinwieruch.de/react-hooks-fetch-data) и до сих пор не смог избежать этого бесконечного l oop.
У меня есть приложение с 2 вкладками, одна из них - это список транспортов и прочее - это сводка активного транспорта. Идея состоит в том, чтобы иметь список транспортов, которые можно забронировать, и всякий раз, когда это будет сделано, обновлять активный транспорт на другой вкладке. Цикл приложения должен быть примерно таким:
- Войти в приложение -> Нет активного транспорта. (Отправьте действие для выборки данных).
- Щелкните вкладку List of Transports (Отправьте действие для получения списка транспортных средств).
- Зарезервируйте транспорт (Отправьте действие для обновления активного транспорта). с выбранным)
- Щелкните вкладку «Активный транспорт» и просмотрите информацию о транспорте.
Идея заключается в том, что всякий раз, когда состояние активного транспорта обновляется, активный Транспортный экран должен быть повторно отрисован, потому что это зависимость в useEffect, но то, что он делает, вызывает бесконечное l oop.
Я понимаю, почему. Чтобы получить активный транспорт из базы данных, у меня есть типичная последовательность отправок (запрос, успех, ошибка), которые изменяют состояние зависимости. И этот запускает бесконечный l oop, потому что каждый раз, когда состояние изменяется, экран перерисовывается, и у меня такая же проблема со списком транспортов.
Даже зная об этом, я все еще не могу знаю, как ее решить.
Я использую следующий активный экран:
Экран ActiveTransport:
export default function ActiveTransportScreen() {
const dispatch = useDispatch();
const isLoading = useSelector(state => state.activeTransport.isLoading);
const transport = useSelector(state => state.activeTransport.transport);
useEffect(() => {
dispatch(activeTransportActions.getActiveTransport());
}, [transport]);
if (isLoading) {
return (
<View style={styles.container}>
<Text>Cargando</Text>
</View>
)
}
if (!transport) {
return (
<View style={styles.container}>
<Text>No hay ningun transporte activo</Text>
</View>
)
}
return (
<View style={styles.container}>
<View style={styles.item}>
<Text>Lugar de retirada: {transport.removalPlace} </Text>
</View>
<View style={styles.containerButtons}/>
<TouchableHighlight
style={{...styles.openButton, backgroundColor: "#2196F3"}}
onPress={() => {
}}
>
<Text style={modalStyles.textStyle}>Completar hito</Text>
</TouchableHighlight>
<TouchableHighlight
style={{...styles.openButton, backgroundColor: "#2196F3"}}
onPress={() => {
dispatch(activeTransportActions.cancelTransport());
}}
>
<Text style={modalStyles.textStyle}>Cancelar</Text>
</TouchableHighlight>
</View>
);
}
Идея, лежащая в основе может повторно отображать ActiveScreen каждый раз при обновлении активного состояния транспорта. И это можно сделать из списка транспортов.
export default function TransportList() {
const dispatch = useDispatch();
const isLoading = useSelector(state => state.transportList.isLoading);
const transportsTablesList = useSelector(state => state.transportList.transports);
const isRefreshing = useSelector(state => state.transportList.isRefreshing);
const modalVisible = useSelector(state => state.modalTransportReducer.modalVisible);
const userActiveTransportId = useSelector(state => state.activeTransport.id);
const onRefresh = React.useCallback(() => {
dispatch(transportActions.refreshTransportList());
}, []);
useEffect( () => {
dispatch(transportActions.getAll());
}, [transportsTablesList ]);
if (isLoading) {
return (
<View style={styles.container}>
<Text>Cargando</Text>
</View>
)
}
if (modalVisible) {
return (
<ModalTransport/>
);
}
if(userActiveTransportId){
return (
<View style={styles.container}>
<Text>¡Ya tienes un transporte activo!</Text>
</View>
)
}
return (
<View style={styles.container}>
<ScrollView horizontal={true}
refreshControl={<RefreshControl refreshing={isRefreshing} onRefresh={onRefresh}/>}>
<FlatList
data={transportsTablesList}
ListHeaderComponent={HeaderListTransport}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => (RowListTransport(item))}
/>
</ScrollView>
</View>
);
}
const initialState =
{
isLoading: false,
id: null,
transport: null,
accomplishment: null,
state: null,
isRefreshing: false
};
export function activeTransport(state = initialState, action) {
switch (action.type) {
case activeTransportConstants.BOOK_TRANSPORT_REQUEST:
return {
...state,
isLoading: true,
id: null,
};
case activeTransportConstants.BOOK_TRANSPORT_SUCCESS:
return {
...state,
isLoading: false,
transport: action.transport,
transportId: action.transportId
};
case activeTransportConstants.BOOK_TRANSPORT_ERROR:
return {
...state,
isLoading: false,
transport: null,
transportId: null
};
case activeTransportConstants.GET_ACTIVE_TRANSPORT_REQUEST:
return {
...state,
isLoading: true,
};
case activeTransportConstants.GET_ACTIVE_TRANSPORT_SUCCESS:
return {
...state,
isLoading: false,
id: action.payload.id,
transport: action.payload.transport,
accomplishment: action.payload.accomplishment,
state: action.payload.state
};
Каждый раз, когда пользователь заказывает транспорт, следующая модальная отправка действия для обновления базы данных и получения активного transport, поэтому вкладку ActiveTransport следует повторно отобразить с информацией о новом транспорте.
export default function ModalTransport() {
const dispatch = useDispatch();
const modalVisible = useSelector(state => state.modalTransportReducer.modalVisible);
const transportSelected = useSelector(state => state.modalTransportReducer.transportSelected);
return(
<View style={modalStyles.centeredView}>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() =>
{
dispatch(transportActions.refreshTransportList());
// dispatch(activeTransportActions.getActiveTransport());
}
}
>
<View style={modalStyles.centeredView}>
<View style={modalStyles.modalView}>
<Text style={modalStyles.modalText}>Transporte</Text>
<Text style={{width: 300, height: 50}}><Text style={{fontWeight: 'bold'}}> Lugar de retirada:</Text> {transportSelected.transportEntity.removalPlace}</Text>
<Text style={{width: 300, height: 50}}><Text style={{fontWeight: 'bold'}}>Lugar de devolución: </Text> {transportSelected.transportEntity.returnPlace}</Text>
<Text style={{width: 300, height: 50}}><Text style={{fontWeight: 'bold'}}>Cliente: </Text>{transportSelected.transportEntity.customer}</Text>
<Text style={{width: 300, height: 50}}><Text style={{fontWeight: 'bold'}}> Carga: </Text>{transportSelected.transportEntity.load}</Text>
<Text style={{width: 300, height: 50}}><Text style={{fontWeight: 'bold'}}>Fecha: </Text> {transportSelected.transportEntity.date} </Text>
<Text style={{width: 300, height: 50}}><Text style={{fontWeight: 'bold'}}>Fecha de caducidad: </Text>{transportSelected.transportEntity.expiryDate} </Text>
<View style={{flexDirection: 'row'}}>
<TouchableHighlight
style={{...modalStyles.openButton, backgroundColor: "#2196F3"}}
onPress={() => {
dispatch(transportActions.bookTransport(transportSelected.id));
dispatch(modalTransportActions.closeModal());
}}
>
<Text style={modalStyles.textStyle}>Reservar</Text>
</TouchableHighlight>
<TouchableHighlight
style={{...modalStyles.openButton, backgroundColor: "#2196F3"}}
onPress={() => {
dispatch(modalTransportActions.closeModal())
}}
>
<Text style={modalStyles.textStyle}>Cancelar</Text>
</TouchableHighlight>
</View>
</View>
</View>
</Modal>
</View>
);
}
Я точно не знаю, что мне делать. Я понимаю, что транспорт - это единственная зависимость в useEffect, и она должна перерисовываться каждый раз при изменении, но я не знаю, как изолировать последовательность запроса, успеха, ошибки, которые меняют состояние каждый раз. Я просто выбираю транспорт из состояния, а не другие части.
Я пробовал использовать useCallback и useMemo, но все еще имею ту же проблему.
Что мне делать?
Надеюсь, ты сможешь мне помочь.
Большое спасибо.