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

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个,并将它们保存到状态.

组件接收itemIdprops (来自React路由).

每当props.itemId改变时,我希望它触发一个效果,在本例中,将其记录到控制台.


问题是,由于效果也依赖于items,因此每当items发生变化时,效果也会运行,例如当按下按钮重新获取items时.

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


What is the best way to trigger an effect dependent on multiple parameters, only when one of the parameters change?


PS. Hooks are kind of a new thing, and I think we all are trying our best to figure out how to properly work with them, so if my way of thinking about this seems wrong or awkward to you, please point it out.

推荐答案

React团队表示,获取prev值的最佳方法是使用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>
  );
}

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

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

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

Reactjs相关问答推荐

尽管在CLI中收到来自Stripe的OK Post请求,但没有webhook Post请求的处理- NextJS 14

过滤对象数组并通过迭代对象数组将属性放入新数组

React onKeyUp不一致地使用快速Shift+键按压

cypress 不能点击SPAN

在Reaction中单击并显示子组件延迟/动画

react -无法获取函数的最新参数值

如何在我的 React 应用程序中仅显示我的 Register 组件

使用以Jest 的方式返回 Promise 的方法来模拟可构造的 API 类时出现问题

console.logs 没有显示在浏览器控制台上,但显示在我的终端上

Chakra UI:如何在选中状态下设置复选框 colored颜色

如何管理可重用无线电输入的 React 状态?

ReactJS 中的图像加载顺序

Firebase查询返回随机用户数据,而不是过滤后的用户数据

臭名昭著的测试未包含在 act(...) 中

如何防止开发人员使用 ESLint 在 React 项目中使用特定的钩子?

如何在悬停时更改 MUI 卡内容

如何使用 React Hook Form 将寄存器作为 props 发送到子组件来收集数据?

如何使用 React 在客户端获取 nestjs websocket 异常错误?

如何使图标适合 react-bootstrap 中的行元素

React如何在用户登录后等待当前用户数据被获取