Reactjs 什么';在useffect中调用事件处理程序道具的好模式是什么?

Reactjs 什么';在useffect中调用事件处理程序道具的好模式是什么?,reactjs,react-hooks,Reactjs,React Hooks,让我们假设一个组件: constfoo=({id,onError})=>{ useffect(()=>{ 订阅(id).catch(error=>onError(error)); return()=>cleanup(id); },[id,onError]); 返回。。。; } 想法很简单——运行一个使用当前“id”订阅的效果。如果订阅失败,请调用作为道具传递的事件处理程序onError 但是,要使其正常工作,传递下来的onErrorprop必须是引用稳定的。换句话说,如果我的组件的使用者尝试了

让我们假设一个组件:

constfoo=({id,onError})=>{
useffect(()=>{
订阅(id).catch(error=>onError(error));
return()=>cleanup(id);
},[id,onError]);
返回。。。;
}
想法很简单——运行一个使用当前“id”订阅的效果。如果订阅失败,请调用作为道具传递的事件处理程序
onError

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

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,使效果每次都运行
const handleError=错误=>{
console.log(“错误”,error);
}
返回
}
相反,他们需要做如下工作:

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

   return <Foo id="test" onError={handleError} />
}
const Parent=()=>{
//handleError标识是稳定的
const handleError=useCallback(错误=>{
console.log(“错误”,error);
},[]);
返回
}
这是可行的,但不知怎么的,我对它不满意。
Foo
的消费者需要意识到
onError
必须是稳定的,这不是显而易见的,除非您查看其底层实现。它打破了组件封装,消费者很容易在没有意识到的情况下遇到问题


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

您需要从依赖项列表中删除
onError
,但如果它发生更改,仍会调用它。为此,您可以使用ref,并在每次渲染时通过
useffect
对其进行更新

如果函数
未定义
,也可以使用来避免调用该函数

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>;
}
constfoo=({id,onError})=>{
const onErrorRef=useRef();
useffect(()=>{
onErrorRef.current=onError;
});
useffect(()=>{
subscribe(id).catch(error=>onErrorRef.current?(error));
return()=>cleanup(id);
},[id]);
返回。。。;
}

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