react reducer中如何异步更新数据?


export enum actionType {
    updateData = 'updateData',
}

export const initData = {
    data: {}
}

const update = () => {
    const age = 'xxx'
    let name = 'xxxx'
    // 这里模拟异步请求
    setTimeout(() => {
        name = '异步数据'
    }, 2000)
    return {
        age,
        name,
    }
}
export const passengerReducer = (state, action) => {
    const data = update()
    switch (action.type) {
        case actionType.updateData:
            return {
                ...state,
                data,
            }
        default:
            return state
    }
}
// 外部调用

dispatch({
     type: updateData
})

之前name的更新是同步更新的没有问题现在需要走接口,等接口返回后再更新,我试过在这个文件中调用dispath但是调用报错,请问下这种异步的数据该怎么更新

阅读 772
avatarAI BotBETA

这个问题是在问如何在 React Reducer 中异步更新数据。

在 Redux 中,reducer 是一个纯函数,它接收当前的 state 和 action,然后返回新的 state。对于异步操作,我们通常在 action creator 中处理它们,而不是在 reducer 中。这是因为 reducer 必须是同步的,而处理异步操作可能会导致不必要的复杂性和错误。

然而,如果你需要在 reducer 中处理异步操作,可以使用某些中间件(例如 redux-thunk 或 redux-saga),这些中间件可以处理异步操作,并在完成后派发一个 action。

在你的代码中,你试图在 reducer 中模拟一个异步操作(使用 setTimeout)。然而,这不会按预期工作,因为 reducer 必须在每次调用时都返回一个新的状态,而你的代码在等待异步操作完成时不会返回任何新的状态。

正确的做法应该是这样的:

  1. 首先,创建一个异步的 action creator,它会在数据加载完成后派发一个 action:
export const fetchData = () => {
    return async dispatch => {
        dispatch({ type: actionType.FETCH_DATA_REQUEST });
        const data = await fetchDataFromServer(); // 模拟异步请求
        dispatch({ type: actionType.FETCH_DATA_SUCCESS, payload: data });
    };
};
  1. 在你的 component 中,当数据加载完成时,派发这个 action:
componentDidMount() {
    this.props.fetchData();
}
  1. 在你的 reducer 中,处理这个 action 并更新 state:
export default function(state = initData, action) {
    switch (action.type) {
        case actionType.FETCH_DATA_REQUEST:
            return state; // 在数据加载期间,保持当前的 state
        case actionType.FETCH_DATA_SUCCESS:
            return { ...state, ...action.payload }; // 用新的数据更新 state
        default:
            return state;
    }
}
2 个回答
const MyComponent = () => {
    const [state, dispatch] = useReducer(passengerReducer, initData);

    useEffect(() => {
        const fetchData = async () => {
            const name = await fetchName(); 
            dispatch({ type: actionType.updateData, payload: { name } });
        };

        fetchData();
    }, []); 

    // 组件其他部分
};

你可以自己封装一个asyncDispatch

const AppContext = createContext();
const AppContextProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, {initState});
  const asyncDispatch = () => {
    dispatch({ type: "loading" });
    fetchData().then(data => {
      dispatch({ type: "finished", payload: data });
    });
  };

  return (
    <AppContext.Provider value={{ state, dispatch: asyncDispatch }}>
      {children}
    </AppContext.Provider>
  );
};

const useAsyncDispatch = () => {
    const context = useContext(AppContext);
    if (context === undefined) {
      throw new Error("useAsyncDispatch must be used within a AppContextProvider");
    }
    const { dispatch } = context;
    return dispatch;
};
推荐问题
logo
Microsoft
子站问答
访问
宣传栏