Nis*_*ano 6 reactjs react-hooks
根据React 文档:
效果函数内引用的每个值也应该出现在依赖项数组中
如果我的效果函数引用了外部作用域中的一些变量,但我只想在其中一个变量发生更改时执行它,为什么我需要指定依赖项数组中的所有其他变量?是的,如果其他变量发生变化,闭包就会变得过时,但我不在乎,因为我还不需要调用该函数。当我关心的变量发生变化时,可以调用具有当时值的新闭包。我缺少什么?
这是一个工作示例(据我所知),其中 useEffect 依赖项数组并不详尽:
import React, { useEffect, useState } from "react";
const allCars = {
toyota: ["camry", "corolla", "mirai"],
ford: ["mustang", "cortina", "model T"],
nissan: ["murano", "micra", "maxima"],
};
function CarList() {
const [cars, setCars] = useState([]);
const [brand, setBrand] = useState("toyota");
const [filterKey, setFilterKey] = useState("");
useEffect(() => {
// I don't want to run this effect when filterKey changes because I wanna wrap that case in a timeout to throttle it.
setCars(allCars[brand].filter(model => model.startsWith(filterKey)));
}, [brand]);
useEffect(() => {
// This effect is only called when filterKey changes but still picks up the current value of 'brand' at the time the function is called.
const timeoutId = setTimeout(() => {
setCars(allCars[brand].filter(model => model.startsWith(filterKey)));
}, 500);
return () => clearTimeout(timeoutId);
}, [filterKey]);
const handleChangeFilterKey = event => {
setFilterKey(event.target.value);
};
return (
<div>
{`${brand} cars`}
<div>Select brand</div>
<input type="radio" value="toyota" checked={brand === "toyota"} onChange={() => setBrand("toyota")} />
<input type="radio" value="ford" checked={brand === "ford"} onChange={() => setBrand("ford")} />
<input type="radio" value="nissan" checked={brand === "nissan"} onChange={() => setBrand("nissan")} />
<div>Filter</div>
<input label="search" value={filterKey} onChange={handleChangeFilterKey} />
<ul>
{cars.map(car => (
<li>{car}</li>
))}
</ul>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
上面的例子有没有什么陷阱?
是的,你应该一直遵循这个规则,当你发现你的代码因遵循它而中断时,这意味着没有遵循良好的实践。这就是这条规则的意义,确保你设计得很好。
我想在你的情况下,代码如下所示:
const Test = () => {
const [wantToSync] = useState(0)
const [notWantToSync] = useState(0) // notWantToSync also might come from props, i'll use state as example here
useEffect(() => {
fetch('google.com', {
body: JSON.stringify({wantToSync, notWantToSync})
}).then(result => {
// ...
})
}, [wantToSync]) // component is supposed to be reactive to notWantToSync, missing notWantToSync in dep is dangerous
}
Run Code Online (Sandbox Code Playgroud)
如果notWantToSync被定义为组件的状态,则该组件应该对其做出反应,包括useEffect。如果这不是您想要的,notWantToSync则不应从一开始就声明。
const Test = () => {
const [wantToSync] = useState(0)
const notWantToSyncRef = useRef(0) // hey I don't want notWantToSync to be reactive, so i put it in useRef
useEffect(() => {
fetch('google.com', {
body: JSON.stringify({wantToSync, notWantToSync: notWantToSyncRef.current})
}).then(result => {
// ...
})
}, [wantToSync, notWantToSyncRef]) // yeah, now eslint doesn't bother me, and notWantToSync doesn't trigger useEffect anymore
}
Run Code Online (Sandbox Code Playgroud)
通常,您不需要在 useEffect 中执行 if else 来停止重新渲染,除了它们具有不同的使用上下文之外,还有其他类似useMemo或useCallback类似的方法useRef。
我在新示例中看到您的挣扎,因此您想做一个节流阀,如果将filterKey其添加到第一个 useEffect dep,则节流阀将被破坏。我的观点是,当您发现自己处于这种情况时,通常意味着有更好的实践(eslint 详尽的帮助识别它),例如,将节流逻辑提取到挂钩: https: //github.com/streamich/react -use/blob/master/src/useThrottle.ts。
详尽的 deps 并不是重要的事情,它只是确保代码设计良好的良好实践。上面的例子证明了
| 归档时间: |
|
| 查看次数: |
3611 次 |
| 最近记录: |