【发布时间】:2019-10-17 16:11:03
【问题描述】:
我正在编写一个以 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 并且不依赖于一些未使用的虚拟状态?
【问题讨论】:
-
@skyboyer 我确实需要最新的日期才能呈现。什么向你表明我没有?是的,我订阅了特定 ID 的数据更改。这个想法是
.onChange(id, handler)执行handler只要该id 的数据发生变化。这就是为什么我对每个 id 更改执行效果。我没有提到这一点,但onChange实际上返回了一个取消订阅函数,然后我在效果中返回了那个取消订阅函数以确保所有处理程序都被清理,所以没有内存泄漏。 -
对不起,第一个和第二个错误,你说不是问题。删除了我的 cmets 具有误导性。
标签: javascript reactjs react-hooks