简体   繁体   中英

How to render a React functional component when useState() changes?

I have a very simple functional component, that gets a date from the localStorage and displays it. I have two buttons to add or remove weeks from the date, and I expect the new date to be shown. However, the component doesn't get rendered.

import React, { useState } from "react";
import { monthList } from "../common/lists";

const Navbar = () => {
  const [focusDate, setFocusDate] = useState(
    Number(localStorage.getItem("focusDate"))
  );

  const [month] = useState(new Date(focusDate).getMonth());
  const [year] = useState(new Date(focusDate).getFullYear());

  const onLeftClick = () => {
    setFocusDate(focusDate - 504000000); //one week
    localStorage.setItem("focusDate", focusDate);
  };

  const onRightClick = () => {
    setFocusDate(focusDate + 504000000);
    localStorage.setItem("focusDate", focusDate);
  };

  return (
    <div className="navbar-container">
      <div className="calendar-navigation-container">
        <div className="navbar-menu-item">
          <i onClick={onLeftClick} className="fas fa-chevron-left"></i>
        </div>
        <div onClick={onRightClick} className="navbar-menu-item">
          <i className="fas fa-chevron-right"></i>
        </div>
        <div className="calendar-year">{`${monthList[month]} ${year}`}</div>
      </div>
    </div>
  );
};

The expected behavior for this component is that it gets the timestamp, then shows the month and the year of that timestamp. When loaded, it properly shows January 2021, however it doesn't render the component when I click several times on onLeftClick, though I was expecting it to show December 2021. The calculations are correct, I think I'm missing here the concept of functional component rendering. This would have been so much easier with Class components, but I want to learn functional ones as well. What am I missing here?

It seems that you expect that setFocusDate is synchronous, wich is not the case . So if you call setFocusDate and, just after that (next line), update the local storage with focusDate, you cannot expect that the local storage contains the new focusDate value. You can read anout this here for example.

In your example I suspect that the local storage update is done with the previous state value because setFocusDate is scheduled but not yet performed by React.

If you want to update the local storage along with the state (sync state with local storage), then you have to use useEffect hook, with focusDate in the dependencies array (second argument for useEffect, so when focusDate changes, useEffect is triggered). :

useEffect(() => {
  // this function will be called after focusDate changed
  // update local storage here
}, [focusDate]);

Beside this, you could use a dedicated hook to sync local storage with a component state like this one: https://usehooks.com/useLocalStorage/

You don't need to make month and year variables part of state, because their value counts just one time. Just assertion will be enough

const month = new Date(focusDate).getMonth();
const year = ew Date(focusDate).getFullYear();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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