Milán Nikolics
Milán Nikolics

Reputation: 621

Why not refresh the select element from context?

I have a simple dropdown. I'ts refresh the state from localstorage and context. The context refresh and I can use everywhere in the page except in the select value.

This dropdown have an default value. (HU,EN,,DE,HR) It's not refresh although the state refresh

I'ts stay 'HU'. Although the state changed. The page other parts work properly

I use hooks. Thank you

Here is my codesandbox:

https://codesandbox.io/s/eager-river-t45b3r?file=/src/LanguageDropDown.js

LanguageDropDown.js

import React, { useState, useContext } from "react";
import GlobalContext from "./GlobalContext";
import classes from "./LanguageDropDown.module.css";
export default function LanguageDropDown() {
  const { language, setLanguage } = useContext(GlobalContext);
  console.log(`This is the  language state from context: ${language}`);
  return (
    <div className={classes.div}>
      <select
        className={classes.languageDropDown}
        value={language}
        onChange={(e) => {
          const selectedLanguage = e.target.value;
          console.log(`this is the selected: ${selectedLanguage}`);
          setLanguage(selectedLanguage);
          localStorage.setItem("language", JSON.stringify(selectedLanguage));
        }}
      >
       <option value="hu">HU</option>
        <option value="en">EN</option>
        <option value="de">DE</option>
        <option value="hr">HR</option>
      </select>
      <h1>Here the good result:{language}</h1>
    </div>
  );
}

ContextWrapper.js

import React, { useState, useEffect } from "react";
import GlobalContext from "./GlobalContext";

export default function ContextWrapper(props) {
  const [language, setLanguage] = useState("");

  useEffect(() => {
    const storageLanguage = localStorage.getItem("language");
    console.log(`this is the storagelanguage: ${storageLanguage}`);
    if (storageLanguage) {
      function setLanguageData() {
        setLanguage(storageLanguage);
      }
      setLanguageData();
    }
  }, [language]);

  return (
    <GlobalContext.Provider
      value={{
        language,
        setLanguage,
      }}
    >
      {props.children}
    </GlobalContext.Provider>
  );
}

Upvotes: 2

Views: 115

Answers (2)

John Landgrave
John Landgrave

Reputation: 1

The answer provided above did not seem to resolve the issue to me (verified by going to the provided code sandbox and it still not working after making that change).

The issue is in the way that you are saving and parsing the value. You are JSON.stringifying the value when storing it, but you are not JSON.parseing it when retrieving it from localStorage. See this code sandbox for a solution: https://codesandbox.io/s/recursing-tree-7sn98k?file=/src/ContextWrapper.js

Alternatively, you could also not JSON.stringify the value when storing it, but considering that localStorage values must be strings (or will be .toString()'d otherwise) I do believe that the approach of stringifying the values on the way in is more fault-tolerant.

Upvotes: 0

poo
poo

Reputation: 1240

Try updating your useEffect to following:

useEffect(() => {
    const storageLanguage = localStorage.getItem("language");
    console.log(`this is the storagelanguage: ${storageLanguage}`);
    if (storageLanguage) {
      function setLanguageData() {
        setLanguage(storageLanguage);
      }
      setLanguageData();
    }
  }, []); //Remove the language from here.

Adding [language] to the dependency array executes the useEffect each time language changes in the dropdown. This inturn set the value of the dropdown again.

Keep the dependency array empty in useEffect, lets useEffect execute only once, that solves the issue.

Upvotes: 1

Related Questions