skip to Main Content

Here I had created a programme to take a different score, and one increment button is present, but the problem is that I want to increment Rik’s score 1 and click the next player, Sam 0, and if I again click on the next player, I want to see Rik’s score 1, but currently it’s showing the score 0, so how to preserve the state of the child when parent rendering is given below. Can I use local storage or context to give any suggestions?

import { useState } from 'react';

export default function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
  return (
    <div>
      {/* {isPlayerA ? (
        <Counter person="Sam" />
      ) : (
        <Counter person="Rik" />
      )} */}
      {isPlayerA && (
        <Counter person="Sam" />
      ) }
      { !isPlayerA &&(
        <Counter person="Rik" />
      )}
      <button onClick={() => {
        setIsPlayerA(!isPlayerA);
      }}>
        Next player
      </button>
    </div>
  );
}

function Counter({ person }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{person}'s score: {score}</h1>
      <button onClick={() => setScore(score + 1)}>
        Add one
      </button>
    </div>
  );
}

2

Answers


  1. In any case, I think it is a good idea to store the score in the component <ScoreBoard/> Because based on your current code, the component <Counter/> will be re-rendered based on the value in isPlayerA. So the score is reset every time you change players.

    I have an alternative here, one drawback is that here I had to predefine the players in the score/setScore hook.

    import { useState } from 'react'
    
    export default function Scoreboard() {
      const [isPlayerA, setIsPlayerA] = useState(true)
      const [score, setScore] = useState({
        Sam: 0,
        Rik: 0
      })
    
      return (
        <div>
          {/* {isPlayerA ? (
            <Counter person="Sam" />
          ) : (
            <Counter person="Rik" />
          )} */}
          {isPlayerA && <Counter person="Sam" score={score} setScore={setScore} />}
          {!isPlayerA && <Counter person="Rik" score={score} setScore={setScore} />}
          <button
            onClick={() => {
              setIsPlayerA(!isPlayerA)
            }}
          >
            Next player
          </button>
        </div>
      )
    }
    
    function Counter({ person, score, setScore }) {
      const [hover, setHover] = useState(false)
    
      let className = 'counter'
      if (hover) {
        className += ' hover'
      }
    
      return (
        <div
          className={className}
          onPointerEnter={() => setHover(true)}
          onPointerLeave={() => setHover(false)}
        >
          <h1>
            {person}'s score: {score[person]}
          </h1>
          <button onClick={() => setScore({ ...score, [person]: (score[person] += 1) })}>
            Add one
          </button>
        </div>
      )
    }
    
    
    Login or Signup to reply.
  2. Using local storage or context are some ways to preserve a child component’s React state. To implement these techniques, try the following:

    1)Local Storage: employing it can do wonders for your data storing needs. With this feature, you can save valuable files and information on the user’s browser, which makes things more efficient. It comes in handy when users want to access it anytime without having to go back and forth to the server. Because it is a part of the HTML5 standard, it is supported by different browsers like Safari, Chrome, and Firefox. On top of that, it is easy to use and gives you extra space to store important data for your program. With local storage, data persistence is taken care of, and you can retrieve vital information without too much hassle.
    Using local storage is a nifty way to save and access player scores from the browser. Check out the revised code below, which incorporates this feature.

    import { useState, useEffect } from 'react';
    
    export default function Scoreboard() {
      const [isPlayerA, setIsPlayerA] = useState(true);
      
      return (
        <div>
          {isPlayerA ? (
            <Counter person="Sam" />
          ) : (
            <Counter person="Rik" />
          )}
          
          <button onClick={() => setIsPlayerA(!isPlayerA)}>
            Next player
          </button>
        </div>
      );
    }
    
    function Counter({ person }) {
      const [score, setScore] = useState(0);
      const [hover, setHover] = useState(false);
    
      let className = 'counter';
      if (hover) {
        className += ' hover';
      }
    
      useEffect(() => {
        // Retrieve the score from local storage when the component mounts
        const savedScore = localStorage.getItem(`${person}_score`);
        if (savedScore) {
          setScore(parseInt(savedScore, 10));
        }
      }, [person]);
    
      useEffect(() => {
        // Save the score to local storage whenever it changes
        localStorage.setItem(`${person}_score`, score.toString());
      }, [person, score]);
    
      return (
        <div
          className={className}
          onPointerEnter={() => setHover(true)}
          onPointerLeave={() => setHover(false)}
        >
          <h1>{person}'s score: {score}</h1>
          <button onClick={() => setScore(score + 1)}>
            Add one
          </button>
        </div>
      );
    }
    

    Each player’s score will be recorded and retrieved from local storage under this approach. This guarantees that the current state will be preserved even if the parent component is re-rendered.

    2)Context comes in handy when it comes to understanding information correctly. It can help us decipher the meaning behind certain phrases or ideas that may otherwise be obscure. With context, we can better understand the message that is being conveyed without ambiguity. It’s essential to consider the surrounding circumstances or events when interpreting something, so as not to misinterpret it. Context provides a richer experience in our comprehension and is a vital element in communicating and understanding information effectively.
    To manage state at a higher level and distribute it to child components, an alternative approach is to utilize React Context. An illustration is provided as follows:

    import { useState, useContext, createContext } from 'react';
    
    // Create a context to hold the score state
    const ScoreContext = createContext();
    
    export default function Scoreboard() {
      const [isPlayerA, setIsPlayerA] = useState(true);
      
      return (
        <ScoreContext.Provider>
          <div>
            {isPlayerA ? (
              <Counter person="Sam" />
            ) : (
              <Counter person="Rik" />
            )}
            
            <button onClick={() => setIsPlayerA(!isPlayerA)}>
              Next player
            </button>
          </div>
        </ScoreContext.Provider>
      );
    }
    
    function Counter({ person }) {
      const [score, setScore] = useContext(ScoreContext);
      const [hover, setHover] = useState(false);
    
      let className = 'counter';
      if (hover) {
        className += ' hover';
      }
    
      return (
        <div
          className={className}
          onPointerEnter={() => setHover(true)}
          onPointerLeave={() => setHover(false)}
        >
          <h1>{person}'s score: {score}</h1>
          <button onClick={() => setScore(score + 1)}>
            Add one
          </button>
        </div>
      );
    }
    

    Using the useContext hook and ScoreContext provider, the Counter component consumes the score state that will be preserved regardless of changes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search