当只有一个效果的 deps 发生变化,而其他的不发生变化时,对 useEffect Hook 做出反应 [英] React useEffect Hook when only one of the effect's deps changes, but not the others

查看:17
本文介绍了当只有一个效果的 deps 发生变化,而其他的不发生变化时,对 useEffect Hook 做出反应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 Hooks 的功能组件:

I have a functional component using Hooks:

function Component(props) {
  const [ items, setItems ] = useState([]);

  // In a callback Hook to prevent unnecessary re-renders 
  const handleFetchItems = useCallback(() => {
    fetchItemsFromApi().then(setItems);
  }, []);

  // Fetch items on mount
  useEffect(() => {
    handleFetchItems();
  }, []);

  // I want this effect to run only when 'props.itemId' changes,
  // not when 'items' changes
  useEffect(() => {
    if (items) {
      const item = items.find(item => item.id === props.itemId);
      console.log("Item changed to " item.name);
    }
  }, [ items, props.itemId ])

  // Clicking the button should NOT log anything to console
  return (
    <Button onClick={handleFetchItems}>Fetch items</Button>
  );
}

组件在挂载时获取一些items并将它们保存到状态.

The component fetches some items on mount and saves them to state.

该组件接收一个 itemId 属性(来自 React Router).

The component receives an itemId prop (from React Router).

每当 props.itemId 发生变化时,我希望它触发一个效果,在这种情况下将其记录到控制台.

Whenever the props.itemId changes, I want this to trigger an effect, in this case logging it to console.

问题在于,由于效果也依赖于items,所以每当items 改变时,效果也会运行,例如当items代码>通过按下按钮重新获取.

The problem is that, since the effect is also dependent on items, the effect will also run whenever items changes, for instance when the items are re-fetched by pressing the button.

这可以通过将之前的 props.itemId 存储在一个单独的状态变量中并比较两者来解决,但这似乎是一个黑客并添加了样板.使用组件类可以通过在 componentDidUpdate 中比较当前和以前的 props 来解决这个问题,但是使用函数式组件是不可能的,这是使用 Hooks 的要求.

This can be fixed by storing the previous props.itemId in a separate state variable and comparing the two, but this seems like a hack and adds boilerplate. Using Component classes this is solved by comparing current and previous props in componentDidUpdate, but this is not possible using functional components, which is a requirement for using Hooks.

仅当其中一个参数发生变化时,触发依赖于多个参数的效果的最佳方法是什么?

附注.Hooks 是一种新事物,我想我们都在尽最大努力弄清楚如何正确地使用它们,所以如果我的想法在你看来是错误或尴尬的,请指出.

推荐答案

React 团队表示,获取 prev 值的最佳方法是使用 useRef:https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state

The React Team says that the best way to get prev values is to use useRef: https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state

function Component(props) {
  const [ items, setItems ] = useState([]);

  const prevItemIdRef = useRef();
  useEffect(() => {
    prevItemIdRef.current = props.itemId;
  });
  const prevItemId = prevItemIdRef.current;

  // In a callback Hook to prevent unnecessary re-renders 
  const handleFetchItems = useCallback(() => {
    fetchItemsFromApi().then(setItems);
  }, []);

  // Fetch items on mount
  useEffect(() => {
    handleFetchItems();
  }, []);

  // I want this effect to run only when 'props.itemId' changes,
  // not when 'items' changes
  useEffect(() => {
    if(prevItemId !== props.itemId) {
      console.log('diff itemId');
    }

    if (items) {
      const item = items.find(item => item.id === props.itemId);
      console.log("Item changed to " item.name);
    }
  }, [ items, props.itemId ])

  // Clicking the button should NOT log anything to console
  return (
    <Button onClick={handleFetchItems}>Fetch items</Button>
  );
}

我认为这对您的情况有帮助.

I think that this could help in your case.

注意:如果不需要之前的值,另一种方法是为props.itemId多写一个useEffect

Note: if you don't need the previous value, another approach is to write one useEffect more for props.itemId

React.useEffect(() => {
  console.log('track changes for itemId');
}, [props.itemId]);

这篇关于当只有一个效果的 deps 发生变化,而其他的不发生变化时,对 useEffect Hook 做出反应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆