React钩子缺少依赖项

时间:2019-09-17 00:19:07

标签: reactjs react-hooks

我希望有人可以在这种情况下向我解释React钩子的正确用法,因为我似乎无法找到它。

以下是我的代码

  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);
  }

所以从本质上讲,我有一个表在其中显示用户,当页面更改,perPage,顺序或类型更改时,我想重新查询用户列表,以便在这种情况下具有useEffect。

现在,通常我会将_getUsers()函数放入该useEffect中,但是唯一的问题是我还有另一个useEffect,当用户在搜索框中开始搜索时,该useEffect才可使用。

我不想用用户在框中输入的每个字母来重新查询我的用户列表,但是我想使用一个在用户停止键入后将触发的去弹器。

因此我自然会创建一个useEffect,它将监视值搜索,每次搜索更改时,我都会调用_debounceSearch函数。

现在我的问题是我似乎无法摆脱React依赖关系警告,因为我在第一个useEffect依赖关系中缺少_getUsers函数,该依赖关系已由_debounceSearch fn使用,在第二个useEffect中,我我第二个useEffect依赖项中缺少_debounceSearch。

我该如何以“正确”的方式重写这种代码,这样我就不会以React警告缺少依赖项而告终?

谢谢!

2 个答案:

答案 0 :(得分:1)

我将设置一个状态变量来保存去抖动的搜索字符串,并有效地用于获取用户。

假设您的组件将查询参数作为道具,它将是这样的:

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 />进行反跳。 在提取组件中执行反跳操作的一个小问题是,搜索中的每项更改都将通过反跳操作,即使它是通过在文本框中键入内容以外的其他方式进行的,例如点击预配置搜索的链接。

答案 1 :(得分:0)

有关钩子依赖关系的规则非常简单明了:如果钩子函数使用或引用了组件范围内的任何变量,则应考虑将其添加到依赖关系列表(https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies)中。

使用您的代码,您应该注意以下几点:

1。对于第一个_getUsers,使用效果:

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])