简体   繁体   中英

React Functional Component is not updating DOM when State Changes

I am trying to update my components but they will not update when a new value is updated in my LocalStorage.

Here is my code:

App.js:

import './App.css';
import CTA from './components/CTA';


function App() {
  return (
    <div className="App">
        <CTA />
    </div>
  );
}

export default App;

The component im having issues with:

The component is looking at localStorage for language selection which is true or false if true, english else, french

But the dom is not updating automatically? It changes when I refresh though...

Kinda a noob...

CTA.js

import * as React from 'react';
import CTA_Image from '../assets/cibc-event.jpeg'
import styles from '../styles/language.module.css'
import useLocalStorage from '../util/store'
import LanguageButtons from './LanguageButtons'


export default function CTA(props) {
    const [isEnglish] = useLocalStorage('isEnglish', true);

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

console.log(isEnglish)
return (
    <>
        <img src={CTA_Image} className={styles.ctaImage} alt='' />

        {isEnglish === true ? 
            <p className={styles.ctaBody}>
                English, i am english, yes
            </p>
        :   <p className={styles.ctaBody}>
                French, parle french, oui
            </p>
        }

        <LanguageButtons />
    </>
)
}

LanguageButton.js:

    import { Button } from "@mui/material"
import useLocalStorage from '../util/store'
import styles from '../styles/language.module.css'

const LanguageButtons = () => {
    const [isEnglish, setEnglish] = useLocalStorage('isEnglish', true);


    let handleLanguage = (props) => {
        setEnglish(props)

        // console.log(isEnglish)
    }
    return (
        <>
            <Button variant="contained" className={styles.languageButton} onClick={()=>handleLanguage(true)}>English</Button>
            <Button variant="contained" className={styles.languageButton} onClick={()=>handleLanguage(false)}>French</Button>
        </>
    )
}

export default LanguageButtons

This is handling the Language Change of course.

store.js - useLocalStorage handling

    import {useState} from 'react';

// Hook
function useLocalStorage(key, initialValue) {
    // State to store our value
    // Pass initial state function to useState so logic is only executed once
    const [storedValue, setStoredValue] = useState(() => {
      if (typeof window === "undefined") {
        return initialValue;
      }
      try {
        // Get from local storage by key
        const item = window.localStorage.getItem(key);
        // Parse stored json or if none return initialValue
        return item ? JSON.parse(item) : initialValue;
      } catch (error) {
        // If error also return initialValue
        console.log(error);
        return initialValue;
      }
    });
    // Return a wrapped version of useState's setter function that ...
    // ... persists the new value to localStorage.
    const setValue = (value) => {
      try {
        // Allow value to be a function so we have same API as useState
        const valueToStore =
          value instanceof Function ? value(storedValue) : value;
        // Save state
        setStoredValue(valueToStore);
        // Save to local storage
        if (typeof window !== "undefined") {
          window.localStorage.setItem(key, JSON.stringify(valueToStore));
        }
      } catch (error) {
        // A more advanced implementation would handle the error case
        console.log(error);
      }
    };
    return [storedValue, setValue];
  }

  export default useLocalStorage;

Any help is appreciated thanks! Apologies for noob question

The different components' calls to useLocalStorage are not linked. So, calling a state setter in one of them won't result in the other one seeing its state change as well.

Call useLocalStorage only once, in a parent component - lift state up . Then, pass down the state value and the state setter to whatever needs it.

export default function CTA(props) {
    const [isEnglish, setEnglish] = useLocalStorage('isEnglish', true);
    return (
        <>
            <img src={CTA_Image} className={styles.ctaImage} alt='' />

            {isEnglish === true ? 
                <p className={styles.ctaBody}>
                    English, i am english, yes
                </p>
            :   <p className={styles.ctaBody}>
                    French, parle french, oui
                </p>
            }

            <LanguageButtons {...{ setEnglish }}/>
        </>
    );
}

and then use the new props:

const LanguageButtons = ({ setEnglish }) => (
    <>
        <Button variant="contained" className={styles.languageButton} onClick={()=>setEnglish(true)}>English</Button>
        <Button variant="contained" className={styles.languageButton} onClick={()=>setEnglish(false)}>French</Button>
    </>
);

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