2

我正在尝试使用反应挂钩来制作一个 Table 组件,该组件根据用户可以选择的一组过滤器显示来自 API 的数据行。我想在用户单击“应用过滤器”按钮时进行新的调用以获取数据,而不是在用户对过滤器进行更改时。

我正在使用上下文来管理“过滤器”状态和“lastFetched”状态,该状态跟踪用户上次单击“应用过滤器”按钮的时间(以及页面上的其他状态)。对上下文的更新是通过 useReducer 钩子及其调度方法进行的(参见此处)。

数据获取发生在 useEffect 挂钩中,只要“lastFetched”状态更改,该挂钩就会重新运行。这似乎工作正常;但是,效果会引用上下文中未包含在依赖项中的其他值(即过滤器)。我知道穷举-deps eslint 规则,我担心我没有正确处理钩子的依赖项。

const Table = () => {
    const [context, dispatch] = useTableContext(); // implemented with createContext and useReducer
    const { filters, lastFetched } = context;

    useEffect(() => {
        if (!filters.run) {
            return;
        }

        dispatch({ type: 'FETCH_DATA_BEGIN' });
        const params = convertContextToParams(context); // this is lazy, but essentially just uses the the filters and some other state from the context 

        API.fetchData(params)
            .then((data) => {
                dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data.results });
            })
            .catch((e) => {
                dispatch({ type: 'FETCH_DATA_FAILURE', payload: e.response.data.message });
            });

        return () => { ... some cleanup... }; 
    }, [lastFetched]); // <== This is the part in question

 return <...some jsx.../>
};

同样,这似乎有效,但根据反应文档,似乎我应该将钩子中使用的上下文中的所有值包含在钩子的依赖项中,以防止过时的引用。这会导致逻辑中断,因为我不想在过滤器更改时获取数据。

我的问题是:当用户单击“应用过滤器”、更新 context.lastFetched 并触发 useEffect 挂钩时,该挂钩是否会从上下文中引用陈旧的过滤器状态?如果是这样,为什么?由于每当单击按钮时都会重新运行效果,并且所有状态更新都是通过 reducer 完成的,所以在闭包中引用陈旧变量的常见危险是否仍然适用?

任何指导表示赞赏!

注意:我考虑过使用 useRef 来防止这个问题,或者可能设计一些自定义异步中间件来获取某些调度的数据,但这是我目前拥有的解决方案。

4

1 回答 1

0

我不是专家,但我想提供我的看法。根据我对 Context 工作原理的理解,您不会在当前实现中获得过时的过滤器数据。useReducer使用将触发Table重新渲染的新对象更新状态。

此外,Table组件并不真正关心过滤器数据,除非lastFetched被点击事件更改。如果lastFetched改变了,所有的ConsumerTableContext都会重新渲染。您也不应该获得陈旧的过滤器数据。

于 2019-09-15T15:16:54.760 回答