Home > Mobile >  How to prevent a component's state from "propagating" on to the next component in a s
How to prevent a component's state from "propagating" on to the next component in a s

Time:06-20

Given a list of sentences, display the first sentence along with a next button. When the next button is clicked display the next sentence, and so on.

While a sentence is displayed, the user should be allowed to highlight individual words by clicking on them. Clicking on a highlighted word "unhighlights" it.

My attempt is shown below (you can run it on StackBlitz: https://slideshow-problem.stackblitz.io/ as well as fork and edit it: https://stackblitz.com/edit/slideshow-problem).

If I highlight the first word of the first sentence and click next, the first word of every subsequent sentence is highlighted as well. Why is this happening when each word and sentence is encapsulated inside their respective components? How can I fix it so that highlighting words of a sentence don't affect the next sentences?

function Slideshow(props: { sentences: string[]; }) {
  const [currentSlideIndex, setCurrentSlideIndex] = useState(0);

  if (currentSlideIndex >= props.sentences.length) {
    return <div>Over.</div>;
  }

  return (
    <div>
      <ProblemComponentController
        sentence={props.sentences[currentSlideIndex]}
      />
      <button onClick={() => setCurrentSlideIndex(currentSlideIndex   1)}>
        Next
      </button>
    </div>
  );
}
function ProblemComponentController(props: { sentence: string; }) {
  const words = props.sentence.split(' ');

  return (
    <p>
      {words.map((w, i) => (
        <span key={i}>
          <ProblemComponent word={w} />{' '}
        </span>
      ))}
    </p>
  );
}
function ProblemComponent(props: { word: string; }) {
  const [isHighlighted, setIsHighlighted] = useState(false);

  return (
    <span
      onClick={() => setIsHighlighted(!isHighlighted)}
      className={isHighlighted ? 'highlight' : ''}
    >
      {props.word}
    </span>
  );
}

CodePudding user response:

You need to add key for the ProblemComponentController to make the component re-initialize.

    <div>
  <ProblemComponentController
    key={currentSlideIndex}
    sentence={props.sentences[currentSlideIndex]}
  />
  <button onClick={() => setCurrentSlideIndex(currentSlideIndex   1)}>
    Next
  </button>
</div>

This is working example. https://stackblitz.com/edit/slideshow-problem-is6anx?file=Slideshow.tsx

  • Related