React hooks - setState не обновляет свойства состояния для отображения боковой панели - PullRequest
1 голос
/ 27 сентября 2019

У меня есть событие, когда вы изменяете размер окна покажет боковую панель рабочего стола или мобильную боковую панель.если окно меньше чем Но есть переменные, которые не обновляются немедленно, чтобы показать боковую панель, если я нахожусь в окне рабочего стола, я мог бы это с классом

Я создал песочницу https://codesandbox.io/s/sidebar-hooks-8oefi дляпосмотрите код, у меня есть компонент класса в App_class.js, который, если я заменю в App, работает, но с перехватами (файл App_hooks.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 ]

2 голосов
/ 27 сентября 2019

Проблема возникает после установки значения isMobile здесь,

setMobile(isMobile => newValueMobile);

Вы немедленно ссылаетесь на это значение,

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

Из-за async природы setState,здесь вы все время получаете предыдущее значение isMobile.

Чтобы выполнить эту работу, вам нужно внести некоторые изменения в свой код.

Вы непосредственно изменяете значение previousWidth, выдолжен иметь previousWidth в состоянии и использовать функцию установки для изменения значения.

const [previousWidth, setPreviousWidth] = useState(-1);

setPreviousWidth(width);  //setter function

Вы не можете получить значение сразу после setState.Вы должны использовать другой useEffect с isMobile и previousWidth в качестве массива зависимостей.

useEffect(() => {
   const wasMobile = previousWidth <= widthLimit;
   if (isMobile !== wasMobile) {
     setOpen(isOpen => !isMobile);
   }
}, [isMobile, previousWidth]);

Демо

0 голосов
/ 27 сентября 2019

Поскольку updateWidth регистрируется один раз при монтировании компонента с помощью useEffect, оно будет ссылаться на состояние устаревшее (isMobile), которое всегда истинно, поэтому 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, нажав на кнопку, вы всегда получите начальное значение при изменении размера браузера (проверьте консоль), и это потому, что logCount относится к состоянию, которое было получено в тот момент, когда оно было определено.

@ ravibagul91 ответ работает, потому что он обращается к состоянию из useEffect, а не из обработчика события.

Вы можете захотеть проверить: Реагировать на поведение перехватчиков с помощью прослушивателя событий и Почему внутри моей функции я вижу устаревшие предметы или состояние? , это даст вам лучшее представление о том, что происходит.

...