通过挂钩传递时,setState函数是否应该是使用效率的依赖性

发布于 2025-01-22 16:25:06 字数 1109 浏览 0 评论 0原文

因此,我偶然发现了这种奇怪的情况:

我有一个全局反应上下文提供商,提供了一个全局状态,例如So

const Context = createContext();

const ContextProvider = ({children}) => {
  const [state, setState] = useState('');
  return <Context.Provider value={{state, setState}}>{children}</Context.Provider>
}

const useMyState = () => {
  const {state, setState} = useContext(Context);

  return {
   state,
   setState
  }
}

const Component = () => {
  const {setState} = useMyState();

  useEffect(() => {
   elementRef.addEventListener('click', () => {
    setState('someState');
   });

   return () => {
    elementRef.removeEventListener('click', () => null); 
   }
  },[])

return <>
 // ...
</>
}

eSlint建议将我的setState添加到useffect的依赖项数组,

useEffect(() => {
   elementRef.addEventListener('click', () => {
    setState('someState');
   });
  },[setState])

我猜这可能与usemystate.ts.ts文件的上下文的破坏有关,

但感觉有些奇怪和非- 直觉...

我的问题是setState在依赖项数组中确实需要吗?如果是这样,为什么?

So, I've stumbled upon this weird situation:

I have a global React Context provider, providing a global state, like so

const Context = createContext();

const ContextProvider = ({children}) => {
  const [state, setState] = useState('');
  return <Context.Provider value={{state, setState}}>{children}</Context.Provider>
}

const useMyState = () => {
  const {state, setState} = useContext(Context);

  return {
   state,
   setState
  }
}

const Component = () => {
  const {setState} = useMyState();

  useEffect(() => {
   elementRef.addEventListener('click', () => {
    setState('someState');
   });

   return () => {
    elementRef.removeEventListener('click', () => null); 
   }
  },[])

return <>
 // ...
</>
}

eslint suggests that my setState should be added to the useEffect's dependency array,

useEffect(() => {
   elementRef.addEventListener('click', () => {
    setState('someState');
   });
  },[setState])

I'm guessing that this might be somehow related to the destructuring of the context inside the useMyState.ts file

but that feels a bit weird and non-intuitive...

my question is is the setState really required inside the dependency array? and if so, why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花桑 2025-01-29 16:25:06

我的问题是setstate在依赖项数组中确实需要吗?

不,不是,但是Eslint不知道,因为它无法知道您使用的上下文对象的setState成员是稳定的。 知道(因为设置器可以通过usestate确保稳定,并且您正在通过上下文和usemystate hook逐字传递它) ,但是Eslint不知道。

您可以将其添加为使Eslint感到高兴的依赖性(如果您已经提供了一个数组,那将不会有任何区别,因为Setter永远不会更改;如果您不是,请参见下面数组),或者您可以发表评论来告诉ESLINT跳过检查该代码,也可以关闭规则(但是非常易于错过依赖项,所以请小心,如果您这样做) 。

(如果您不提供数组[因为您希望在每个渲染后运行效果],则在其中添加一个带有设置器的数组将停止发生这种情况,因此您需要选择禁用ESLINT的选项 错误的解决方案,例如在其中使用带有越来越多的数字值的Ref。


对于这种情况,有 它反复将新事件的听众添加到元素中,而无需删除它们,因为使用 no 依赖项数组,useffect cownback每次compents渲染时都会调用,并且您正在创建创建每次都有一个新的活动处理程序功能,因此它们会堆叠。

因此,您需要将elementRef.current作为依赖关系,并且需要一个清理回调:

const Component = () => {
    const {setState} = useMyState();
  
    useEffect(() => {
        const handler = () => {
            setState("someState");
        };
        const element = elementRef.current;
        // Note −−−−−−−−−−−−−−−−−−^^^^^^^^
        element.addEventListener("click", handler);
        return () => {
            element.removeEventListener("click", handler);
        };
    }, [elementRef.current]); // <== Optionally add `setState` to this

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

my question is is the setState really required inside the dependency array?

No, it isn't, but ESLint doesn't know that, because it has no way to know that the setState member of the context object you're using is stable. You know that (because the setter is guaranteed to be stable by useState, and you're passing it verbatim through context and your useMyState hook), but ESLint doesn't know that.

You can add it as a dependency to make ESLint happy (it won't make any difference if you're already providing an array, because the setter never changes; see below if you're not providing an array), or you can put in a comment to tell ESLint to skip checking that code, or you can turn the rule off (but it's very easy to miss out dependencies, so be careful if you do).

(If you're not providing an array [because you want the effect to run after every render], adding an array with the setter in it will stop that from happening, so you'll want to go with the option of disabling the ESLint error for that one situation. Or there are icky solutions like using a ref with an ever-increasing number value in it. :-) )


There is a problem with that code, though. It's repeatedly adding new event listeners to the element without ever removing them, because with no dependency array, the useEffect callback is called every time the component renders, and you're creating a new event handler function every time, so they'll stack up.

So you'll need to make elementRef.current a dependency, and you'll need a cleanup callback:

const Component = () => {
    const {setState} = useMyState();
  
    useEffect(() => {
        const handler = () => {
            setState("someState");
        };
        const element = elementRef.current;
        // Note −−−−−−−−−−−−−−−−−−^^^^^^^^
        element.addEventListener("click", handler);
        return () => {
            element.removeEventListener("click", handler);
        };
    }, [elementRef.current]); // <== Optionally add `setState` to this

    return <>
        // ...
    </>;
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文