Бесконечный L oop выборка данных в использовании Эффект с React Native Hooks и Redux - PullRequest
0 голосов
/ 21 июня 2020

Мне не удалось решить проблему, связанную с бесконечными циклами с использованием 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, но все еще имею ту же проблему.

Что мне делать?

Надеюсь, ты сможешь мне помочь.

Большое спасибо.

...