React Hooks:为什么省略 create 或 useEffect 和 useCallback 的回调是不好的?
React Hooks: Is there a reason why leaving out the create or respectively the callback for useEffect and useCallback is bad?
所以我正在阅读 "A complete Guide to useEffect" by Dan Abramov and the Hooks docs。
Dan在文章中举了下面的例子:
function SearchResults() {
const [query, setQuery] = useState('react');
// ✅ Preserves identity until query changes
const getFetchUrl = useCallback(() => {
return 'https://hn.algolia.com/api/v1/search?query=' + query;
}, [query]); // ✅ Callback deps are OK
useEffect(() => {
const url = getFetchUrl();
// ... Fetch data and do something ...
}, [getFetchUrl]); // ✅ Effect deps are OK
// ...
}
Hook 文档给出了这个:
function ProductPage({ productId }) {
// ✅ Wrap with useCallback to avoid change on every render
const fetchProduct = useCallback(() => {
// ... Does something with productId ...
}, [productId]); // ✅ All useCallback dependencies are specified
return <ProductDetails fetchProduct={fetchProduct} />;
}
function ProductDetails({ fetchProduct })
useEffect(() => {
fetchProduct();
}, [fetchProduct]); // ✅ All useEffect dependencies are specified
// ...
}
我在想:回调和工厂函数真的有必要吗?
你也可以这样写:
const getFetchUrl = useCallback('https://hn.algolia.com/api/v1/search?query=' + query, [query]);
和
useEffect(fetchProduct, [fetchProduct]);
类似地,您可以想到这样一种场景,您可以将创建函数排除在外 useMemo
:
function Greeting({ name }) {
const calculateExpensive = useCallback(() => {
return `Hello ${name}`;
}, [name]);
const result = useMemo(calculateExpensive, [calculateExpensive]);
return <p>{result}</p>;
}
我确定我在这里犯了一个愚蠢的错误。我没有看到和做错了什么?
使用 useCallback
的原因是在需要时在渲染之间保持对函数的相同引用。
顾名思义,useCallback
应该接受回调函数作为参数。由于 useCallback(fn)
是 useMemo(() => fn)
的快捷方式,从技术上讲,它可以(误)与任何参数一起使用:
const getFetchUrl = useCallback('https://hn.algolia.com/api/v1/search?query=' + query, [query]);
这样做没有任何好处,因为 useMemo
和 useCallback
旨在用于惰性求值,而这会导致急切求值。
带有 getFetchUrl
回调的示例不是很能说明问题,因为 memoization 没有提供任何改进,它可以简化为:
function SearchResults() {
const [query, setQuery] = useState('react');
const fetchUrl = 'https://hn.algolia.com/api/v1/search?query=' + query;
useEffect(() => {
// ... Fetch data and do something ...
}, [fetchUrl]);
}
至于Greeting
的例子,useCallback
是多余的。如果计算真的很昂贵并且需要延迟评估(在本例中不是),这就是 useMemo
的用途:
function Greeting({ name }) {
const result = useMemo(() => {
return `Hello ${name}`;
}, [name]);
return <p>{result}</p>;
}
所以我正在阅读 "A complete Guide to useEffect" by Dan Abramov and the Hooks docs。
Dan在文章中举了下面的例子:
function SearchResults() {
const [query, setQuery] = useState('react');
// ✅ Preserves identity until query changes
const getFetchUrl = useCallback(() => {
return 'https://hn.algolia.com/api/v1/search?query=' + query;
}, [query]); // ✅ Callback deps are OK
useEffect(() => {
const url = getFetchUrl();
// ... Fetch data and do something ...
}, [getFetchUrl]); // ✅ Effect deps are OK
// ...
}
Hook 文档给出了这个:
function ProductPage({ productId }) {
// ✅ Wrap with useCallback to avoid change on every render
const fetchProduct = useCallback(() => {
// ... Does something with productId ...
}, [productId]); // ✅ All useCallback dependencies are specified
return <ProductDetails fetchProduct={fetchProduct} />;
}
function ProductDetails({ fetchProduct })
useEffect(() => {
fetchProduct();
}, [fetchProduct]); // ✅ All useEffect dependencies are specified
// ...
}
我在想:回调和工厂函数真的有必要吗?
你也可以这样写:
const getFetchUrl = useCallback('https://hn.algolia.com/api/v1/search?query=' + query, [query]);
和
useEffect(fetchProduct, [fetchProduct]);
类似地,您可以想到这样一种场景,您可以将创建函数排除在外 useMemo
:
function Greeting({ name }) {
const calculateExpensive = useCallback(() => {
return `Hello ${name}`;
}, [name]);
const result = useMemo(calculateExpensive, [calculateExpensive]);
return <p>{result}</p>;
}
我确定我在这里犯了一个愚蠢的错误。我没有看到和做错了什么?
使用 useCallback
的原因是在需要时在渲染之间保持对函数的相同引用。
useCallback
应该接受回调函数作为参数。由于 useCallback(fn)
是 useMemo(() => fn)
的快捷方式,从技术上讲,它可以(误)与任何参数一起使用:
const getFetchUrl = useCallback('https://hn.algolia.com/api/v1/search?query=' + query, [query]);
这样做没有任何好处,因为 useMemo
和 useCallback
旨在用于惰性求值,而这会导致急切求值。
带有 getFetchUrl
回调的示例不是很能说明问题,因为 memoization 没有提供任何改进,它可以简化为:
function SearchResults() {
const [query, setQuery] = useState('react');
const fetchUrl = 'https://hn.algolia.com/api/v1/search?query=' + query;
useEffect(() => {
// ... Fetch data and do something ...
}, [fetchUrl]);
}
至于Greeting
的例子,useCallback
是多余的。如果计算真的很昂贵并且需要延迟评估(在本例中不是),这就是 useMemo
的用途:
function Greeting({ name }) {
const result = useMemo(() => {
return `Hello ${name}`;
}, [name]);
return <p>{result}</p>;
}