【问题标题】:Only navigate to next page when asynchronos actions are complete? React-native仅在异步操作完成后导航到下一页?反应原生
【发布时间】:2026-01-28 14:00:01
【问题描述】:

所以,作为一个使用 redux 和 react-native 的初学者,我在这里遇到了一些棘手的情况。

当用户登录时,我想用用户数据更新 Redux 状态。我调用了一个登录方法,在那里我得到了一个网络令牌。紧接着我想用 redux-thunk 调度两个异步操作。问题是:

当这些动作被分派并且我得到来自 API 的响应时,我已经导航到另一个屏幕并且呈现列表的数据不处于 Redux 状态。

问题:我怎样才能“保持”程序直到我的状态更新,然后导航到下一页?

这是用户登录时发生的情况:

 fetch("http://10.0.2.2:8000/api/api-token-auth/", {
        method: "post",
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          email: this.props.email,
          password: this.props.password,
        })
        }).then((response) => response.json()
        ).then((jResponse) => {
          console.log(jResponse);
          this._onValueChange('token_id', jResponse.token);
          this.props.loginUserSuccess();
          this.props.navigation.navigate('MainMenue');
        }).catch((error) => {
          console.log(error);
          this.props.loginUserFail();
          })   
    }

在登录期间的某个地方,这两个动作应该被完全调度并且状态应该被更新:

export const profileLoad = () => {       

        return (dispatch) => {
            AsyncStorage.getItem('token_id')
            .then((token_id) => fetch("http://10.0.2.2:8000/api/profile/", {
                method: "GET",
                headers: {
                'Authorization': 'JWT ' + token_id
                }
            })
            .then((response) => response.json())
            .then((answer) => {
                dispatch({ type: PROFILE_LOAD, payload: answer});
            })
            .done());
        }  
    }

export const productsLoad = () => {

    return (dispatch) => {
        AsyncStorage.getItem('token_id')
        .then((token_id) => {

            fetch("http://10.0.2.2:8000/api/profile/products/", {
                method: "GET",
                headers: {
                'Authorization': 'JWT ' + token_id
                }
            }).then((anser) => anser.json())
            .then((response)=> {
                dispatch ({ type: PRODUCTS_LOAD, payload: response})
            })
        }
        ).done();
    }  

}

然后我想导航另一个屏幕并渲染一个列表(使用 ListView)以显示来自产品和配置文件的 JSON 数据。

--> 所以我终于想通了。 解决方案 1.) 如所述返回动作创建者的承诺 2.) 确保在 then 方法中放置一个回调函数

export const loadAllProfileData = ({navigate}) => {
    return (dispatch) => {
        dispatch(profileLoad())
        .then(() => dispatch(productsLoad()))
        .then(() => navigate('MainMenue'))
    };
}

export const profileLoad = () => {       

            return (dispatch) => {
                return AsyncStorage.getItem('token_id')
                .then((token_id) => fetch("http://10.0.2.2:8000/api/profile/", {
                    method: "GET",
                    headers: {
                    'Authorization': 'JWT ' + token_id
                    }
                })
                ).then((response) => response.json())
                .then((answer) => {
                    dispatch({ type: PROFILE_LOAD, payload: answer});
                })

            }  
        }


export const productsLoad = () => {

     return (dispatch) => {
         return AsyncStorage.getItem('token_id')
         .then((token_id) => 
             fetch("http://10.0.2.2:8000/api/profile/products/", {
                 method: "GET",
                 headers: {
                 'Authorization': 'JWT ' + token_id
                 }
            })
        ).then((answer) => answer.json())
        .then((response)=> {
                dispatch ({ type: PRODUCTS_LOAD, payload: response})
            }) 

     }  
}

【问题讨论】:

    标签: react-native redux


    【解决方案1】:

    您可以通过then 回复您的动作创建者和chain 他们的承诺。您只需将return AsyncStorage.getItem() ... 添加到您的动作创建者即可。然后你可以这样做:

    fetch(url) //login
      .then(dispatch(profileLoad))
      .then(dispatch(productsLoad))
      .then(this.props.navigation.navigate('MainMenue'))
      .catch(err => //handle error)
    

    阅读更多关于promises chaining的信息。

    编辑:一个简单的例子是:

    import { createStore, applyMiddleware } from 'redux'
    import thunkMiddleware from 'redux-thunk'
    import fetch from 'node-fetch';
    
    const ROOT_URL = 'https://jsonplaceholder.typicode.com';
    
    const FETCH_DATA = 'FETCH_DATA';
    
    const url = `${ROOT_URL}/users`;
    
    function fetchData() {
        return (dispatch) => {
            return fetch(url)
                .then(res => res.json())
                .then(data => {
                    dispatch({
                        type: FETCH_DATA,
                        payload: data[0].name
                    });
                }) 
        }
    }
    
    function reducer(state = [], action) {
        if (action.type === FETCH_DATA) {
            console.log('Action.payload:', action.payload);
        }
    
        switch (action.type) {
            case 'FETCH_DATA':
                return [...state, action.payload];
    
            default:
                return state;
        };
    }
    
    let store = createStore(
        reducer,
        applyMiddleware(thunkMiddleware)
    )
    
    store.subscribe(() =>
        console.log('Store State: ', store.getState())
    )
    
    fetch(url)
        .then(res => res.json())
        .then(data => data)
        .then(store.dispatch(fetchData()))
        .then(store.dispatch(fetchData()))
    

    【讨论】:

    • 所以现在动作创建者正在返回:return AsyncStorage.getItem() 你的意思是删除所有对调度的调用而不是返回回调函数吗?这似乎让我感到困惑,因为在动作创建者中必须分派某种动作......
    • 您将保持调度原样,返回 Promise 的原因是您可以等待获取到resolve,然后再转到下一个。
    • 抱歉所有这些愚蠢的问题。但是调度功能是由 thunk 中间件提供的,对吧?我可以简单地在组件级别上调用它​​吗?登录是否也必须是 redux 操作?在那里我使用了组件级状态。现在我只是得到 dispatch 没有定义。
    • 是的,由于thunk,可以使用dispatch功能。如果使用 redux connect 传递它,则可以在组件级别调用它。如果您不想在其中使用 dispatch,则登录不必是 redux 操作。用一个简单的例子编辑了我的答案,我使用了一个不是 thunk 的 fetch,然后是两个 thunk。 LMK,如果你不能理解的东西。
    • 我在这个问题上花了更多的时间,然后我想向任何人承认。我将更新的代码发布到我原来的问题中。但它就是行不通。