反应挂钩-setState不会更新状态属性以显示侧边栏

时间:2019-09-27 00:10:01

标签: javascript reactjs react-hooks

调整大小时,我有一个事件,窗口将显示桌面侧边栏或移动侧边栏。如果window小于,但是如果我在桌面窗口中,有些变量不会立即更新以显示侧边栏,我可以使用class

我已经创建了一个沙箱https://codesandbox.io/s/sidebar-hooks-8oefi 要查看代码,我在App_class.js中具有类组件,如果在App中替换它,它可以工作,但是带有钩子(App.hoos.js文件,默认情况下在App.js中),我无法使其工作

感谢您的关注。我期待着您的答复。

在课堂上,我可以使用:

if (isMobile !== wasMobile) {
   this.setState({
      isOpen: !isMobile
   });
}
 const App = props => {
  //minicomponent to update width
  const useListenResize = () => {
    const [isOpen, setOpen] = useState(false);
    const [isMobile, setMobile] = useState(true);
    //const [previousWidth, setPreviousWidth] = useState( -1 );

    let previousWidth = -1;

    const updateWidth = () => {
      const width = window.innerWidth;
      const widthLimit = 576;
      let newValueMobile = width <= widthLimit;
      setMobile(isMobile => newValueMobile);
      const wasMobile = previousWidth <= widthLimit;

      if (isMobile !== wasMobile) {
        setOpen(isOpen => !isMobile);
      }
      //setPreviousWidth( width );
      previousWidth = width;
    };

    useEffect(() => {
      updateWidth();
      window.addEventListener("resize", updateWidth);
      return () => {
        window.removeEventListener("resize", updateWidth);
      };
      // eslint-disable-next-line
    }, []);

    return isOpen;
  };

  const [isOpen, setOpen] = useState(useListenResize());

  const toggle = () => {
    setOpen(!isOpen);
  };

  return (
    <div className="App wrapper">
      <SideBar toggle={toggle} isOpen={isOpen} />
      <Container fluid className={classNames("content", { "is-open": isOpen })}>
        <Dashboard toggle={toggle} isOpen={isOpen} />
      </Container>
    </div>
  );
};

export default App;

使用setState无效

2 个答案:

答案 0 :(得分:2)

问题是在此处设置isMobile值后

setMobile(isMobile => newValueMobile);

您将立即引用该值,

if (isMobile !== wasMobile) {
   setOpen(isOpen => !isMobile);
}

由于async的{​​{1}}性质,您一直在这里得到setState的先前值。

要执行此操作,您需要对代码进行一些更改。

您正在直接更改isMobile的值,您应该使previousWidth处于一种状态,并使用setter函数更改该值。

previousWidth

const [previousWidth, setPreviousWidth] = useState(-1); setPreviousWidth(width); //setter function 之后,您无法立即获得价值。您应该使用另一个setStateuseEffect作为依赖项数组的isMobile

previousWidth

Demo

答案 1 :(得分:0)

由于updateWidth使用useEffect在组件安装中注册一次,因此它将引用陈旧状态(isMobile),该状态始终为真,因此{{ 1}}将永远无法使用。

编辑:以下code说明了您问题的更简单版本:

setOpen(isOpen => !isMobile)

如果运行此代码,您会注意到,即使通过单击按钮更改const Counter = () => { const [count, setCount] = useState(0) const logCount = () => { console.log(count); } useEffect(() => { window.addEventListener('resize', logCount); }, []) return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ) } 的值,在调整浏览器大小时也始终会获得初始值(请检查控制台),这就是因为count指的是在定义之时获得的状态。

@ ravibagul91答案有效,因为它从logCount而不是从事件处理程序访问状态。

您可能想要检查:React hooks behaviour with event listenerWhy am I seeing stale props or state inside my function?,它将使您对发生的事情有更好的了解。