разрешение состояния гонки по вызову API - PullRequest
1 голос
/ 06 марта 2020

У меня проблема из-за асинхронного вызова c. У меня есть действие, которое делает вызов API и выдвигает на страницу Dashboard. Этот вызов API также обновляет state.account.id в зависимости от ответа, который он возвращает:

const submitLogin = e => {
        e.preventDefault();
        props.loginAndGetAccount(credentials);
        props.history.push('/protected');
        e.target.reset();
    }

loginAndGetAccount исходит от этого действия:

export const loginAndGetAccount = credentials => dispatch => {
    dispatch({ type: GET_ACCOUNT_START })
    axios
        .post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
        .then(res => {
            console.log(res);
            dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
            localStorage.setItem("token", res.data.token)
        })
        .catch(err => console.log(err));
}

На странице панели инструментов у меня есть useEffect, настроенный для динамического вызова другого API на основе значения, хранящегося в state.account.id. Однако, похоже, что первый вызов API передается на страницу Dashboard, прежде чем ответ возвращается и обновляется state.account.id. Поэтому, когда второй вызов API делается там, он передает state.account.id этому динамическому вызову API 1020 * как неопределенный, что, конечно, приводит к неудачному вызову. Как я могу решить это? Вот что происходит:

const Dashboard = props => {
    const [accountInfo, setAccountInfo] = useState({});

    useEffect(() => {
            console.log(props.accountId);
            axiosWithAuth()
                .get(`/operator/${props.accountId}`)
                .then(res => {
                    console.log(res);
                })
                .catch(err => console.log(err));
    }, [])

    return (
        <div>
            <h1>This is the Dashboard component</h1>
        </div>
    )
}

const mapStateToProps = state => {
    return {
        accountId: state.account.id
    }
}

export default connect(mapStateToProps, {})(Dashboard);

enter image description here

1 Ответ

2 голосов
/ 06 марта 2020

Проблема root в том, что вы делаете запрос здесь, но не

export const loginAndGetAccount = credentials => dispatch => {
    dispatch({ type: GET_ACCOUNT_START })
    axios
        .post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
        .then(res => {
            console.log(res);
            dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
            localStorage.setItem("token", res.data.token)
        })
        .catch(err => console.log(err));
}

, ожидая его завершения, прежде чем перейти к следующей странице

const submitLogin = e => {
        e.preventDefault();
        props.loginAndGetAccount(credentials);
        props.history.push('/protected');
        e.target.reset();
    }

Самый быстрый способ исправить это - вернуть обещание от loginAndGetAccount, а затем props.history.push в разрешении этого обещания ...

вот так:

export const loginAndGetAccount = credentials => dispatch => {
    dispatch({ type: GET_ACCOUNT_START })
    // return the promise here
    return axios
        .post('https://foodtrucktrackr.herokuapp.com/api/auth/login/operators', credentials)
        .then(res => {
            console.log(res);
            dispatch({ type: GET_ACCOUNT_SUCCESS, payload: res.data.id })
            localStorage.setItem("token", res.data.token)
        })
        .catch(err => console.log(err));
}

...


const submitLogin = e => {
    e.preventDefault();
    props.loginAndGetAccount(credentials)
        .then(() => {
            // so that you can push to history when it resolves (the request completes)
            props.history.push('/protected');
            e.target.reset();
        }
        .catch(e => {
            // handle the error here with some hot logic
        })
}
...