我无法使用useEffect解决与React Hooks和Redux的无限循环有关的问题。 我已经阅读了许多有关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),但仍然无法避免这种无限循环。
我确实有一个带有2个选项卡的应用程序,其中一个是传输列表,另一个是活动传输的摘要。 这个想法是要有一个可以预订的运输清单,并且每当完成时,在另一个选项卡中更新活动的运输。 应用程序的周期应类似于:
其背后的想法是,每当更新活动传输的状态时,都必须重新渲染活动传输屏幕,因为它是useEffect的依赖项,但是它会触发无限循环。
我明白为什么。为了从数据库中获取活动的传输,我使用了典型的调度序列(Request,Success,Error),这些调度会更改依赖项的状态。这会触发无限循环,因为每次状态更改时,屏幕都会重新呈现,并且传输列表也存在相同的问题。
即使知道这一点,我仍然不知道如何解决。
我正在使用的活动屏幕是下一个屏幕:
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
};
每次用户预订运输时,下一个Modal都会调度操作以更新数据库并获取活动的运输,因此,应该使用新运输的信息重新呈现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,但仍然存在相同的问题。
我该怎么办?
希望您能帮助我。
非常感谢您。