简体   繁体   English

在 React 中使用 state 的正确方法

[英]Correct way to use state in React

Update:更新:

So I tried to figure it out, but couldn't.所以我试图弄清楚,但不能。 I have an onClick that triggers the toggleNavbar function.我有一个触发切换导航栏 function 的toggleNavbar

I also have the windowResized function which checks if the browser is wider than 576. If that condition is true it checks if the navbarState is true.我还有windowResized function 检查浏览器是否宽于 576。如果该条件为真,则检查navbarState是否为真。 If both conditions are true the toggleNavbar function should be called from the windowResized function.如果两个条件都为真,则应从toggleNavbar function 调用windowResized function。

The issue that I'm having is that the if statement below (the one in the windowResized function) never runs, because the state doesn't update.我遇到的问题是下面的 if 语句( windowResized函数中的那个)永远不会运行,因为 state 没有更新。

if (navbarState) {
  toggleNavbar()
}

Is there a way to make sure that the navbarState updates before I do the checks?有没有办法在我进行检查之前确保 navbarState 更新?

navbar.js导航栏.js

import React, { useState, useRef, useEffect } from "react"
import { Link } from "gatsby"
import styles from "./styling/navbar.module.less"

const Navbar = ( props ) => {

  const [navbarState, setNavbarState] = useState(false)
  const [navHeight, setNavHeight] = useState()
  const ref = useRef(null)

  useEffect(() => {
    let windowResized = () => {
      let windowWidth = window.innerWidth
      if (windowWidth > 576) {
        if (navbarState) {
          toggleNavbar()
        }
      }
    }
    window.addEventListener('resize', windowResized)

    setNavHeight(ref.current.clientHeight)
  }, [])

  let toggleNavbar = () => {
    setNavbarState((navbarState) => !navbarState)
    if (navbarState) {
      props.updateClassNames(styles.contentLeftAnimate)
    }
    else{
      props.updateClassNames(styles.contentRightAnimate)
    }
  }
    
  return (
    <nav ref={ref} id={"navigation-bar"}>
      <div className={`${styles.navLinks} ${navbarState? styles.navActive:""}`} 
      style={{top: `${navHeight}px`}}>
        {props.pages.map((page, index) => (
          <Link key={page.name} className={`${styles.navLink} ${styles.navLinkHoverEffect} ${navbarState? styles.navAnimate:""}`} 
          style={{animationDelay: `${index / 7 + 0.5}s`}} to={page.link}>
              {page.name}
          </Link>
        ))}
      </div>
      <div className={`${styles.burger} ${navbarState? styles.toggle:""}`} onClick={toggleNavbar}>
        <div className={styles.line1}></div>
        <div className={styles.line2}></div>
        <div className={styles.line3}></div>
      </div>
    </nav>
  )
}

export default Navbar

You never set navbarState to false again, also put adding event listeners in an effect is better so try this instead:您再也不会将 navbarState 设置为 false ,而且将添加事件侦听器效果更好,因此请尝试以下操作:

//only set the event listener on mount
useEffect(() => {
  let windowResized = () => {
    let windowWidth = window.innerWidth;

    if (windowWidth > 576) {
      // if (navbarState) { this was a stale closure
      setNavbarState(false);
      console.log('Toggle navbar - Width > 576');
    } else {//not sure if you need this else
      console.log('Window is bigger than mobile');
      //set it to true again when it goes over 576 (not sure if you need this)
      setNavbarState(true);
    }
  };
  window.addEventListener('resize', windowResized);
  //probably never happens to layout but if unmounted
  //  remove the event listener
  return () =>
    window.removeEventListener('resize', windowResized);
}, []);

The toggle is probably wrong as well if you expect navbarState to immediately change after calling setNavbarState, instead try this如果您希望 navbarState 在调用 setNavbarState 后立即更改,则切换也可能是错误的,而是试试这个

setNavbarState((navbarState) => {
  const newState = !navbarState;
  if (newState) {
    props.updateClassNames(styles.contentLeftAnimate);
  } else {
    props.updateClassNames(styles.contentRightAnimate);
  }
  return newState;
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM