1

After reading the docs for useState and useEffect I cant figure out what i'm doing wrong here... Im trying to dynamically update my h1 title with an updated title when a tab is clicked, however the state will not update so my title wont rerender.

This is my subheader component which takes in an array of objects as props. These objects are iterated over and used to populate the subnav bar. (which works as intended).

const Subheader = (props) => {
    const {
        submenuItems = []
    } = props;

    // State
    const  [pageTitle, setPageTitle] = useState(submenuItems[0].name); //Sets starting value as the first item of my submenu which is also the default route so works as intended.

    const handleMenuItemClick = (name) => {
            setPageTitle(name)
            console.log(name) //This prints out the updated expected value
            console.log(pageTitle) //This prints out the original not updated value

    }

    const submenuItemsJSX = submenuItems.map((item, index) => {
        return (
                <li
                key={index}
                to={item.to}
                onClick={() => handleMenuItemClick(item.name)}
                >
                  <a>
                    {item.name}
                  </a>
                </li>
        )
    });

    useEffect(() => {
      console.log(pageTitle) //This prints out the original not updated value
    }, [pageTitle])


    return (
      <div>
        <div>
          <h1>
            {pageTitle}  //This is what i want to update
          </h1>
        </div>
        <div>
          <ul>
            {submenuItemsJSX}
          </ul>
        </div>
      </div>
    )
}

export default Subheader

a sample of whats coming in through the subMenuItems:

{name: 'Categories', to: '/settings/categories', buttons: [] }
Cheekumz
  • 61
  • 14
  • Does this answer your question? [useState set method not reflecting change immediately](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) – Emile Bergeron Dec 17 '20 at 15:31
  • Also notice that `const [selected`? It can't change at all since it's a `const`. – Emile Bergeron Dec 17 '20 at 15:32
  • const is fine, please check how to use state in react hook - https://reactjs.org/docs/hooks-state.html @EmileBergeron – wangdev87 Dec 17 '20 at 15:33
  • Is your confusion with `console.log` only @William's comment covers that... Or do you actually have some issues with the printed `pageTitle` value? – Nemanja Lazarevic Dec 17 '20 at 15:35
  • @WilliamWang never said it wasn't fine, it's to highlight to OP that even if it was sync, it wouldn't be able to change because it's ALSO a `const`. – Emile Bergeron Dec 17 '20 at 15:37
  • @NemanjaLazarevic the issue is with the value of PageTitle not changing and so on screen display is not being rerendered to reflect the new title. The console log was just me checking to see if changed. – Cheekumz Dec 17 '20 at 15:40
  • can you check console.log(name) if name changes? – wangdev87 Dec 17 '20 at 15:41
  • With what's in the question, the code looks fine, but we're missing too much to tell why it doesn't update. Please provide a [mcve]. (Remove any unnecessary component, provide the minimal dataset to reproduce the problem, etc.) – Emile Bergeron Dec 17 '20 at 15:44
  • @WilliamWang name changes as expected in a console.log(name) – Cheekumz Dec 17 '20 at 15:44
  • 1
    then `pageTitle` would be updated inside render. – wangdev87 Dec 17 '20 at 15:46
  • first, check the pageTitle updates inside the useEffect as i indicated in my answer below. – wangdev87 Dec 17 '20 at 15:48
  • updated to remove irrelevant code – Cheekumz Dec 17 '20 at 15:54
  • @WilliamWang it does not. After adding a console.log for name into my `handleMenuItemClick` and adding in the useEffect from your answer the console spits out 1 correct for the (name) and 2 incorrects. – Cheekumz Dec 17 '20 at 15:57
  • please update your question how you used useEffect. – wangdev87 Dec 17 '20 at 15:58
  • @WilliamWang updated to be clearer hopefully. – Cheekumz Dec 18 '20 at 09:51

3 Answers3

3

setSelectedMenuItem and setPageTitle are the asynchronous method, and you can't get the updated value of selected and pageTitle immediately after setSelectedMenuItem() and setPageTitle().

You should use useEffect to check the updated value with adding dependency.

useEffect(() => {
  console.log(selected)
}, [selected])

useEffect(() => {
  console.log(pageTitle)
}, [pageTitle])
wangdev87
  • 8,611
  • 3
  • 8
  • 31
  • Yes but how he will be able to get the updated value from useEffect hook to the JSX? he needs to show it dynamically in the JSX, not just to console log it from the useEffect. – Jeton Dec 17 '20 at 15:43
  • 1
    @Jeton that's done automatically, that's how useEffect knows the value has changed. – Emile Bergeron Dec 17 '20 at 16:09
  • @EmileBergeron I know, but Cheekumz issue is that, value it's not updated in the JSX too, not only to console.log it. – Jeton Dec 17 '20 at 16:13
  • 1
    @Jeton it wasn't (and still isn't) clear from OP's question when William wrote his answer. OP didn't provide a reproducible example, so the code shown in the question might be completely irrelevant. – Emile Bergeron Dec 17 '20 at 16:17
  • @EmileBergeron Have tried to clarify in my recent edit – Cheekumz Dec 18 '20 at 09:52
1

Your code appears to be correct. The issue must be somewhere else. I've made a codesandbox demo and everything works.

Ivan V.
  • 7,593
  • 2
  • 36
  • 53
  • thanks for this, it hasn't helped figure out my problem, it has however convinced me to continue working on it and not find an alternative solution, as this is my preferred route. – Cheekumz Dec 28 '20 at 09:09
-1

Have you tried to pass empty string '' to useState, when you declare the pageTitle? And for initialisation of the value you can use useEffect hook.

const [pageTitle, setPageTitle] = useState('');

useEffect(() => {
  setPageTitle(submenuItems[0].name)
})
Jeton
  • 44
  • 7