React 功能组件:一旦达到 window 断点就尝试设置状态

React functional component: Trying to set a state once a window break point is reached

这是我的问题代码,我的问题是事件在到达 960px 断点时触发了多次。这应该只在到达断点时触发,但我得到的事件触发器数量几乎呈指数级增长。

 const mediaQuery = '(max-width: 960px)';
 const mediaQueryList = window.matchMedia(mediaQuery);
 mediaQueryList.addEventListener('change', (event) => {
   if (event.matches) {
     setState((prevState) => ({
       ...prevState,
       desktopNavActivated: false,
     }));
   } else {
     setState((prevState) => ({
       ...prevState,
       menuActivated: false,
       navItemExpanded: false,
     }));
   }
 });```

您好,欢迎来到 Whosebug!

  1. 我假设,当我第一次开始使用效果时,您的代码在 useEffect hook, which will result in a new event listener being added to your mediaQueryList every time your component gets updated/rendered. This would explain the exponential amount of triggers. The useEffect hook can be quite unintuitive at first, so I recommend reading up on it a bit. The docs do quite a good job at explaining the concept. I also found this article by Dan Abramov 内不会 运行 非常有用。

  2. 你调用 setState 函数的方式总是会导致你的组件更新,无论当前状态是否已经匹配你的媒体查询,因为你每次都向它传递一个新对象更新。与基于 class 的组件的 setState 方法(比较对象 key/values iirc)不同,hook 版本仅在确定更新是否应触发重新渲染时检查 strict equality .一个例子:

{ foo: 'bar' } === { foo: 'bar' } // Always returns false. Try it in your console. 

为了防止这种情况发生,您可以设置一个状态挂钩,它实际上只跟踪比赛结果并从中派生出您的标志。布尔值在引用相等时工作得很好:

const [doesMatch, setDoesMatch] = useState(false)

所以把它们放在一起:

const mediaQuery = '(max-width: 960px)';
const mediaQueryList = window.matchMedia(mediaQuery);


const MyComponent = () => 
   const [match, updateMatch] = useState(false)
   useEffect(() => {
      const handleChange = (event) => {
          updateMatch(event.matches)
      } 
      mediaQueryList.addEventListener('change', handleChange)
      return () => {
         // This is called the cleanup phase aka beforeUnmount
         mediaQueryList.removeEventListener('change', handleChange)   
      }
   }, []) // Only do this once, aka hook-ish way of saying didMount
   
   const desktopNavActivated = !match

   // ...
   // Further process your match result and return JSX or whatever
}

再一次,我真的建议你在有空的时候仔细阅读 React 文档和一些文章。 Hooks 很棒,但如果不了解基本概念,使用它们会很快变得非常令人沮丧。