如何避免useEffect挂钩中的setState导致第二次渲染

时间:2019-06-01 07:34:49

标签: javascript reactjs react-hooks

我正在编写一个以id为输入的自定义钩子,然后应执行以下任务:

  • 从商店同步获取该id的数据
  • 订阅此存储中的更改并相应地更新数据

我想出了以下实现,其缺点是我直接从效果钩子内部设置状态,从而导致第二次渲染。

function useData({id}) {
    // set initial data on first render
    const [data, setData] = useState(Store.getData(id));

    useEffect(() => {
        // when id changes, set data to whatever is in store at the moment
        // here we call setData directly from inside useEffect, causing a second render
        setData(Store.getData(id));
        // subscribe to changes to update data whenever it changes in the store
        return Store.onChange(id, setData);
    }, [id]);

    return data;
}

我尝试的第二种方法是添加一个虚拟状态,该状态仅会导致重新渲染。在这种方法中,我直接返回从Store.getData()接收的数据。这样可以确保每次渲染时都能获得最新数据,而useEffect可以确保每个onChange触发器都将导致新的渲染。

function useData({id}) {
    // adding some dummy state that we only use to force a render
    const [, setDummy] = useState({});
    const refresh = useCallback(() => {
        setDummy({});
    }, []);

    useEffect(() => {
        // subscribe to changes cause a refresh on every change
        return Store.onChange(id, refresh);
    }, [id, refresh]);

    return Store.getData[id];
}

第二种方法效果很好,但是添加此虚拟状态感觉很奇怪。当然,我可以将其放入另一个useRefresh挂钩中,但是我不确定这是否真的是一个好习惯。

是否有更好的方法来实现此目的,而无需直接从useEffect内部调用setData且不依赖于一些未使用的伪状态?

1 个答案:

答案 0 :(得分:0)

因此,到目前为止,一旦更改存储,您就可以在钩子内部使用useState来重新触发宿主组件的呈现。从外面带变化处理程序怎么样?

function useData(id, onChanged) {
  useEffect(() => {
    return store.onChange(id, onChanged);
  }, [id, onChanged]);

 return store.getData(id);
}