【问题标题】:What's a good pattern for invoking event handler props in useEffect?在 useEffect 中调用事件处理程序道具的好模式是什么?
【发布时间】:2021-06-16 08:04:19
【问题描述】:

让我们假设一个组件:

const Foo = ({id, onError}) => {
    useEffect(() => {
        subscribe(id).catch(error => onError(error));
        return () => cleanup(id);
    }, [id, onError]);

  return <div>...</div>;
}

这个想法很简单——运行一个使用当前“id”订阅的效果。如果订阅失败,则调用一个事件处理程序onError,该处理程序作为道具向下传递。

但是,要使其正常工作,传递下来的 onError 属性必须在引用上是稳定的。换句话说,如果我的组件的消费者尝试了以下操作,他们可能会遇到为每个渲染运行效果的问题:

const Parent = () => {
   // handleError is recreated for each render, causing the effect to run each time
   const handleError = error => {
     console.log("error", error);
   }

   return <Foo id="test" onError={handleError} />
}

相反,他们需要执行以下操作:

const Parent = () => {
   // handleError identity is stable
   const handleError = useCallback(error => {
     console.log("error", error);
   },[]);

   return <Foo id="test" onError={handleError} />
}

这有效,但我对它有点不满意。 Foo 的消费者需要意识到 onError 必须是稳定的,除非您查看其底层实现,否则这不是显而易见的。它破坏了组件封装,消费者很容易在不知不觉中遇到问题。

是否有更好的模式来管理可以在useEffect 中调用的事件处理程序等道具?

【问题讨论】:

  • 您确定组件上的onError 事件处理程序是处理来自subscribe 的错误的正确位置。我会尝试让订阅处理它自己的错误。在这种情况下,您希望处理什么样的错误?
  • @HåkenLid 假设Foo 是一个可重用的组件,每个消费者可能以不同的方式处理错误。它不一定是onError,它可以是任何事件(onSubscribed、onDataReceived 等)。我只是想举一个简单的例子。

标签: reactjs react-hooks


【解决方案1】:

你需要从你的依赖列表中删除onError,但是如果它改变了仍然调用。为此,您可以使用 ref,并在每次渲染时通过 useEffect 更新它。

如果是undefined,您也可以使用optional chaining ?. 来避免调用该函数。

const Foo = ({ id, onError }) => {
  const onErrorRef = useRef(); 
  
  useEffect(() => {
    onErrorRef.current = onError;
  });

  useEffect(() => {
    subscribe(id).catch(error => onErrorRef.current?.(error));
    return () => cleanup(id);
  }, [id]);

  return <div>...</div>;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-31
    • 2021-09-29
    • 1970-01-01
    • 2020-03-06
    • 2022-08-02
    • 2014-11-27
    • 2021-10-23
    • 1970-01-01
    相关资源
    最近更新 更多