React hook 缺少依赖
我希望有人能向我解释在这种情况下 React hook 的正确用法,因为我似乎找不到解决方法。
以下是我的代码
useEffect(() => {
_getUsers()
}, [page, perPage, order, type])
// This is a trick so that the debounce doesn't run on initial page load
// we use a ref, and set it to true, then set it to false after
const firstUpdate = React.useRef(true);
const UserSearchTimer = React.useRef()
useEffect(() => {
if(firstUpdate.current)
firstUpdate.current = false;
else
_debounceSearch()
}, [search])
function _debounceSearch() {
clearTimeout(UserSearchTimer.current);
UserSearchTimer.current = setTimeout( async () => {
_getUsers();
}, DEBOUNCE_TIMER);
}
async function _getUsers(query = {}) {
if(type) query.type = type;
if(search) query.search = search;
if(order.orderBy && order.order) {
query.orderBy = order.orderBy;
query.order = order.order;
}
query.page = page+1;
query.perPage = perPage;
setLoading(true);
try {
await get(query);
}
catch(error) {
console.log(error);
props.onError(error);
}
setLoading(false);
}
所以本质上我有一个显示用户的表,当页面发生变化、每个页面、顺序或类型发生变化时,我想重新查询我的用户列表,因此我有一个 useEffect 用于这种情况。
现在一般我会将 _getUsers() 函数放入该 useEffect 中,但唯一的问题是我还有另一个 useEffect 用于当我的用户开始在搜索框中搜索时。
我不想使用用户在框中输入的每一个字母重新查询我的用户列表,而是想使用在用户停止输入后触发的防抖动器。
所以很自然地我会创建一个 useEffect,它会监视值搜索,每次搜索发生变化时,我都会调用我的 _debounceSearch 函数。
现在我的问题是我似乎无法摆脱 React 依赖警告,因为我的第一个 useEffect 依赖项中缺少 _getUsers 函数,该函数被我的 _debounceSearch fn 使用,而在我的第二个 useEffect 中,我的第二个 useEffect 依赖项中缺少 _debounceSearch。
我怎样才能以“正确”的方式重写它,这样我就不会最终收到有关缺少依赖项的 React 警告?
提前致谢!
我将设置一个状态变量来保存去抖动的搜索字符串,并使用它获取用户。
假设您的组件将查询参数作为 props,它将是这样的:
function Component({page, perPage, order, type, search}) {
const [debouncedSearch, setDebouncedSearch] = useState(search);
const debounceTimer = useRef(null);
// debounce
useEffect(() => {
if(debounceTime.current) {
clearTimeout(UserSearchTimer.current);
}
debounceTime.current = setTimeout(() => setDebouncedSearch(search), DEBOUNCE_DELAY);
}, [search]);
// fetch
useEffect(() => {
async function _getUsers(query = {}) {
if(type) query.type = type;
if(debouncedSearch) query.search = debouncedSearch;
if(order.orderBy && order.order) {
query.orderBy = order.orderBy;
query.order = order.order;
}
query.page = page+1;
query.perPage = perPage;
setLoading(true);
try {
await get(query);
}
catch(error) {
console.log(error);
props.onError(error);
}
setLoading(false);
}
_getUsers();
}, [page, perPage, order, type, debouncedSearch]);
}
在初始渲染时,去抖动效果将设置一个去抖动计时器……但没关系。
去抖动延迟后,它将设置
deboucedSearch
状态为相同值。
由于 deboucedSearch 没有改变,ferch 效果将不会运行,因此不会浪费获取。
随后,在更改除搜索之外的任何查询参数时,获取效果将立即运行。 在更改搜索参数时,获取效果将在去抖动后运行。
但理想情况下,去抖动应该在搜索参数的
<input />
处完成。
在获取组件中进行去抖动的小问题是,搜索中的每个更改都将经过去抖动,即使它是通过文本框输入以外的方式发生的,例如单击预配置搜索的链接。
围绕钩子依赖关系的规则非常简单明了:如果钩子函数使用或引用组件范围内的任何变量,则应考虑将其添加到依赖项列表中( https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies )。
对于您的代码,您应该注意以下几点:
1.使用第一个
_getUsers
useEffect:
useEffect(() => {
_getUsers()
}, [page, perPage, order, type])
// Correctly it should be:
useEffect(() => {
_getUsers()
}, [_getUsers])
此外,您的
_getUsers
函数当前在每次重新渲染组件时都会重新创建,你可以考虑使用
React.useCallback
来记忆它。
2.第二个
useEffect
useEffect(() => {
if(firstUpdate.current)
firstUpdate.current = false;
else
_debounceSearch()
}, [search])
// Correctly it should be
useEffect(() => {
if(firstUpdate.current)
firstUpdate.current = false;
else
_debounceSearch()
}, [firstUpdate, _debounceSearch])