你(可能)不需要 useState + useEffect。
`and`useState和 ` useEffecthooks` 对 React 社区来说简直是天赐之物。然而,任何工具都一样,它们也很容易被滥用。
以下是我在软件开发生涯中经常看到的一种误用示例:
const MyAwesomeComponent = () => {
const [loading, setLoading] = useState(true);
const [data, setData] = useState();
// ---- PROBLEMATIC HOOKS: ----
const [items, setItems] = useState([]);
const [itemsLength, setItemsLength] = useState(0);
useEffect(() => {
someAsyncApiCall().then(res => {
setData(res.data);
setLoading(false);
});
}, [setData, setLoading]);
// ---- UNNECESSARY USAGE OF HOOKS: ----
// anytime data changes, update the items & the itemsLength
useEffect(() => {
setItems(data.items);
setItemsLength(data.items.length || 0);
}, [data, setItems, setItemsLength]);
return (
// ...JSX
);
};
上述用例的问题在于我们跟踪了一些冗余状态,具体来说是items和itemsLength。这些数据可以通过函数从 中导出data。
更好的方法:
任何可以从其他数据推导出的数据都可以用纯函数进行抽象和重写。
其实这很容易做到——举个例子:
const getItems = (data) => {
// I always like to protect against bad/unexpected data
if (!data || !data.items) return [];
return data.items;
};
const getItemsLength = (data) => {
return getItems(data).length;
};
然后,我们的组件简化为以下形式:
const MyAwesomeComponent = () => {
const [loading, setLoading] = useState(true);
const [data, setData] = useState();
// DERIVED DATA - no need to keep track using state:
const items = getItems(data);
const itemsLength = getItemsLength(data);
useEffect(() => {
someAsyncApiCall().then(res => {
setData(res.data);
setLoading(false);
});
}, [setData, setLoading]);
return (
// ...JSX
);
};
要点总结
这种模式的优点在于,对于给定的输入,输出始终相同,因此很容易为其编写单元测试getItems。getItemsLength
或许上面的例子有点牵强,但这绝对是我多年来在很多代码库中看到的一种模式。
随着应用程序规模的扩大,尽可能降低复杂性对于避免技术债务至关重要。
tl;dr:
使用useState钩子useEffect函数往往不可避免,但如果可以,尽量将任何可以从其他数据派生出来的数据抽象出来,使用纯函数。这样做的好处会在日后带来巨大的回报。
横幅照片由Lautaro Andreani在Unsplash上拍摄
文章来源:https://dev.to/townofdon/you-probously-dont-need-that-usestate-useeffect-3ijh