首页 > 解决方案 > 在钩子中使用异步数据初始化 useReducer

问题描述

首先,一些背景。

我有一个异步加载数据的功能组件。

const { error, loading, data, getAllData } = useData(); // useData is a custom hook abstracting Context API

if (error) return <Error error={error} />;
if (!data || loading) return <LinearProgress />;

{/* etc .. */}

所以data是异步加载的,这意味着它最初是未定义的,但是当异步加载完成时,它会获得一些真正的价值。

现在我需要在表格中显示数据,对于表格,我想将一些逻辑抽象到一个钩子中。

所以我最终有

const { error, loading, data, getAllData } = useData();
const tableCtrl = useTable(data);

if (error) return <Error error={error} />;
if (!data || loading) return <LinearProgress />;

useTable.ts我有

export function useTable(initialItems: TableItem[]): TableCtrl {
    const [state, dispatch] = React.useReducer(reducer, {
        items: initialItems,
        selectedItems: [],
        allSelected: false
    });

    return {
        ...state,
        deleteItem: (itemToDelete: TableItem) =>
            dispatch({ type: 'delete_item', item: itemToDelete }),
        selectAll: () => dispatch({ type: 'select_all' }),
        selectNone: () => dispatch({ type: 'select_none' }),
        select: (item: TableItem) => dispatch({ type: 'select', item }),
        deselect: (item: TableItem) => dispatch({ type: 'deselect', item })
    };
}

现在我很确定你可以发现问题,但是initialData钩子用来创建它的useReducerundefined它并且它从来没有真正更新它。因此,当真实数据“到达”时,它不会更新钩子的状态。

我该如何解决这个问题?

标签: reactjs

解决方案


这是个有趣的问题。因为 hook ofReact.useReducer只取初始值一次,那么它会保持状态本身,而不需要再次设置值。

所以这个想法很简单。您只需在dispatch每次data更改时通过导出的功能再次设置您的状态。这是想法片段:

让我们创建一个导出函数来更新您的状态useTable.ts


return {
 setData: data => dispatch(/* This is where you set your state again */)
}

现在调用setDatadata在主文件中所做的更改:

const { setData, ...others } = useTable(data);

React.useEffect(() => {
  if (data) {
   // This will sync your state with the latest data
   setData(data);
  }
}, [data])

推荐阅读