根据我的经验,像这样通过props 传递未记忆的函数并不常见。
// don't do this
<Wrapper
getWebsites={() => fetchJson('websites').then(setWebsites)}
loadUserRatings={() => fetchJson('ratings').then(setUserRatings)}
/>
如果它们被正确记忆(使用像useCallback() 这样的钩子,或者通过在任何组件之外定义),那么可以安全地将它们传递给useEffect() 的deps,而不会产生任何行为差异。这是一个修复上述情况的示例。*
// do this
const fetchJson = (...args) => fetch(...args).then(res => res.json());
const Parent = () => {
const [websites, setWebsites] = useState([]);
const [userRatings, setUserRatings] = useState({});
// useCallback creates a memoized reference
const getWebsites = useCallback(
() => fetchJson('websites').then(setWebsites),
[setWebsites]
);
const loadUserRatings = useCallback(
() => fetchJson('ratings').then(setUserRatings),
[setUserRatings]
);
...
<Wrapper
getWebsites={getWebsites}
loadUserRatings={loadUserRatings}
/>
* useState() 在其返回值中存储调度函数,因此从技术上讲,将[] 作为deps 传递给每个useCallback() 是安全的,但我相信指定调度函数因为依赖项通过明确传达作者的意图有助于提高清晰度,并且传递它们没有任何缺点。
Ramesh's answer 足以应付这种情况。
如果你发现你被第一个场景卡住了,那么,作为最后的手段,你可以像这样将props初始化为你的组件的状态。
const Wrapper = (props) => {
const [{ getWebsites, loadUserRatings }] = useState(props);
useEffect(() => {
getWebsites();
loadUserRatings();
}, [getWebsites, loadUserRatings]);
return (
<>
<Header />
<Websites />
<Sync />
</>
);
};