useEffect 中的所有变量都绝对需要列为依赖项吗?
Are all variables inside a useEffect absolutely required to be listed as dependencies?
useEffect 中使用的所有变量是否始终、绝对、无一例外地需要指定为依赖项?
我的用例(为演示目的而简化)涉及根据浏览器 window 的宽度执行的不同功能,但当浏览器 window 更改时 运行 不执行:
const scrollToTop = () => window.scrollTo(0, 0)
const scrollToTopOfArticle = () => window.scrollTo(0, 200)
function App({
isDesktop,
selectedArticle
}) {
useEffect(() => {
isDesktop ? scrollToTop() : scrollToTopOfArticle()
}, [selectedArticle])
return (
<div className="App">
<h1>{selectedArticle.title}</h1>
<p>{selectedArticle.body}</p>
</div>
);
}
如果我将 isDesktop 添加到依赖项中,那么只要用户在移动设备和桌面之间调整 window 的大小,就会产生 运行s 的效果,这是不希望的,但我也知道教条效果中使用的所有内容都必须列为依赖项。
关于如何协调这两个要求有什么建议吗?
Are all variables inside a useEffect absolutely required to be listed as dependencies?
是,否则会产生警告。
这就是为什么最好清楚每个效果应该做什么(即关注点分离)。
因此,您可以拥有两个具有不同依赖关系的独立效果。
类似于:
useEffect(
() => {
scrollToTopOfArticle();
}, [selectedArticle]
);
useEffect(
() => {
if (selectedArticle && isDesktop) {
scrollToTop();
}
}, [isDesktop, selectedArticle]
)
如果您想让 useEffect()
仅响应 selectedArticle
中的更改,请使用 isDesktop
和 selectedArticle
来初始化组件状态。每当 selectedArticle
发生变化时,第一个 useEffect()
将使用传入的道具更新两个状态,并触发第二个 useEffect()
在下一次渲染时重新 运行。
const scrollToTop = () => window.scrollTo(0, 0)
const scrollToTopOfArticle = () => window.scrollTo(0, 200)
function App({
isDesktop,
selectedArticle
}) {
const [desktop, setDesktop] = useState(isDesktop)
const [article, setArticle] = useState(selectedArticle)
useEffect(() => {
if (article !== selectedArticle) {
setDesktop(isDesktop)
setArticle(selectedArticle)
}
}, [isDesktop, selectedArticle, article])
useEffect(() => {
if (desktop) scrollToTop()
else scrollToTopOfArticle()
}, [desktop, article])
return (
<div className="App">
<h1>{selectedArticle.title}</h1>
<p>{selectedArticle.body}</p>
</div>
)
}
或者,您可以将此锁定行为抽象为另一个挂钩,以便 isDesktop
仅在 selectedArticle
更改时更新其实时值。请注意,selectedArticle
仍然需要成为滚动动作效果的依赖项,因此 useEffect()
将在每次更改为 selectedArticle
时触发滚动动作,即使 isDesktop
没有自上次触发以来更改的值。
const useLatch = (value, deps) => {
const [state, setState] = useState(value)
const effect = useCallback(() => { setState(value) }, [value])
useEffect(effect, deps)
return state
}
const scrollToTop = () => window.scrollTo(0, 0)
const scrollToTopOfArticle = () => window.scrollTo(0, 200)
function App({
isDesktop,
selectedArticle
}) {
const latchedIsDesktop = useLatch(isDesktop, [selectedArticle])
useEffect(() => {
if (latchedIsDesktop) scrollToTop()
else scrollToTopOfArticle()
}, [latchedIsDesktop, selectedArticle])
return (
<div className="App">
<h1>{selectedArticle.title}</h1>
<p>{selectedArticle.body}</p>
</div>
)
}
useEffect 中使用的所有变量是否始终、绝对、无一例外地需要指定为依赖项?
我的用例(为演示目的而简化)涉及根据浏览器 window 的宽度执行的不同功能,但当浏览器 window 更改时 运行 不执行:
const scrollToTop = () => window.scrollTo(0, 0)
const scrollToTopOfArticle = () => window.scrollTo(0, 200)
function App({
isDesktop,
selectedArticle
}) {
useEffect(() => {
isDesktop ? scrollToTop() : scrollToTopOfArticle()
}, [selectedArticle])
return (
<div className="App">
<h1>{selectedArticle.title}</h1>
<p>{selectedArticle.body}</p>
</div>
);
}
如果我将 isDesktop 添加到依赖项中,那么只要用户在移动设备和桌面之间调整 window 的大小,就会产生 运行s 的效果,这是不希望的,但我也知道教条效果中使用的所有内容都必须列为依赖项。
关于如何协调这两个要求有什么建议吗?
Are all variables inside a useEffect absolutely required to be listed as dependencies?
是,否则会产生警告。
这就是为什么最好清楚每个效果应该做什么(即关注点分离)。
因此,您可以拥有两个具有不同依赖关系的独立效果。
类似于:
useEffect(
() => {
scrollToTopOfArticle();
}, [selectedArticle]
);
useEffect(
() => {
if (selectedArticle && isDesktop) {
scrollToTop();
}
}, [isDesktop, selectedArticle]
)
如果您想让 useEffect()
仅响应 selectedArticle
中的更改,请使用 isDesktop
和 selectedArticle
来初始化组件状态。每当 selectedArticle
发生变化时,第一个 useEffect()
将使用传入的道具更新两个状态,并触发第二个 useEffect()
在下一次渲染时重新 运行。
const scrollToTop = () => window.scrollTo(0, 0)
const scrollToTopOfArticle = () => window.scrollTo(0, 200)
function App({
isDesktop,
selectedArticle
}) {
const [desktop, setDesktop] = useState(isDesktop)
const [article, setArticle] = useState(selectedArticle)
useEffect(() => {
if (article !== selectedArticle) {
setDesktop(isDesktop)
setArticle(selectedArticle)
}
}, [isDesktop, selectedArticle, article])
useEffect(() => {
if (desktop) scrollToTop()
else scrollToTopOfArticle()
}, [desktop, article])
return (
<div className="App">
<h1>{selectedArticle.title}</h1>
<p>{selectedArticle.body}</p>
</div>
)
}
或者,您可以将此锁定行为抽象为另一个挂钩,以便 isDesktop
仅在 selectedArticle
更改时更新其实时值。请注意,selectedArticle
仍然需要成为滚动动作效果的依赖项,因此 useEffect()
将在每次更改为 selectedArticle
时触发滚动动作,即使 isDesktop
没有自上次触发以来更改的值。
const useLatch = (value, deps) => {
const [state, setState] = useState(value)
const effect = useCallback(() => { setState(value) }, [value])
useEffect(effect, deps)
return state
}
const scrollToTop = () => window.scrollTo(0, 0)
const scrollToTopOfArticle = () => window.scrollTo(0, 200)
function App({
isDesktop,
selectedArticle
}) {
const latchedIsDesktop = useLatch(isDesktop, [selectedArticle])
useEffect(() => {
if (latchedIsDesktop) scrollToTop()
else scrollToTopOfArticle()
}, [latchedIsDesktop, selectedArticle])
return (
<div className="App">
<h1>{selectedArticle.title}</h1>
<p>{selectedArticle.body}</p>
</div>
)
}