Home > OS >  Revert state for second click
Revert state for second click

Time:10-03

I'm having trouble managing to revert a state. What I'm trying to achieve is when I click a play button (PlayContainer) I change the content inside {play}. This function works but I'm having trouble reverting the change on another click {stop}. (I'm using styled components so elements have set names.)

export default function Play() {

  const [play, setStatus] = useState(() => {
    return (
      <RadioContainer>
        <PlayButton src="/img/play.svg" />
      </RadioContainer>
    );
  });

  function start() {
    setStatus(() => {
      return (
        <RadioContainerSecond onClick={stop}>
          <PlayButton src="/img/pause.svg" />
          <Video
            width="560"
            height="315"
            src="https://www.youtube.com/embed/21qNxnCS8WU?autoplay=1&controls=0"
            title="YouTube video player"
            frameborder="0"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
          />
        </RadioContainerSecond>
      );
    });
  }

  function stop() {
    setStatus(() => {
      return (
        <RadioContainer>
          <PlayButton src="/img/play.svg" />
        </RadioContainer>
      );
    });
  }

  return (
    <OuterCircle>
      <InnerCircle>
        <PlayContainer onClick={start}>{play}</PlayContainer>
      </InnerCircle>
    </OuterCircle>
  );
}

Maybe I'm going about this wrong, please let me know if there are any easier or better methods out there.

CodePudding user response:

I think it's better to use a boolean for play instead of a component. You can then toggle the component based on the play boolean like this:

export default function Play() {
    const [play, setPlay] = useState(false); // Boolean instead of component

    function start() {
      setPlay(true); // Simply toggle boolean
    }

    function stop() {
      setPlay(false); // Simply toggle boolean
    }

    return (
        <OuterCircle>
            <InnerCircle>
                <PlayContainer onClick={start}>
          {
          {/* Toggle between the 2 components based on the play boolean */}
          play
           {/* If play is true use RadioContainerSecond */}
            ? (<RadioContainerSecond onClick={stop}>
                <PlayButton src="/img/pause.svg" />
                <Video
                  width="560"
                  height="315"
                  src="https://www.youtube.com/embed/21qNxnCS8WU?autoplay=1&controls=0"
                  title="YouTube video player"
                  frameborder="0"
                  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                />
              </RadioContainerSecond>)
            {/* If play is false use RadioContainer */}
              : (<RadioContainer>
                  <PlayButton src="/img/play.svg" />
                </RadioContainer>)
        }
        </PlayContainer>
            </InnerCircle>
        </OuterCircle>
    );
}

CodePudding user response:

Storing JSX in React state is generally anti-pattern in React. You should store data and render your UI from the data stored in state. Store a boolean value in state to represent the play/stop state and conditionally render one element or the other based on the current state.

export default function Play() {
  const [play, setStatus] = useState(false);

  function start() {
    setStatus(true);
  }

  function stop() {
    setStatus(false);
  }

  return (
    <OuterCircle>
      <InnerCircle>
        <PlayContainer onClick={start}>
          {play ? (
            <RadioContainerSecond onClick={stop}>
              <PlayButton src="/img/pause.svg" />
              <Video
                width="560"
                height="315"
                src="https://www.youtube.com/embed/21qNxnCS8WU?autoplay=1&controls=0"
                title="YouTube video player"
                frameborder="0"
                allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
              />
            </RadioContainerSecond>
          ) : (
            <RadioContainer>
              <PlayButton src="/img/play.svg" />
            </RadioContainer>
          )}
        </PlayContainer>
      </InnerCircle>
    </OuterCircle>
  );
}

CodePudding user response:

There are some issues in your code. Firstly, you are storing a JSX elements in a state which is a bad idea. Secondly this component has 2 return statements (it should give an error). Your code can be updated to this instead:

export default function Play() {

  const [play, setStatus] = useState(false)

  const mainComponent = !play 
      ? <RadioContainer>
          <PlayButton src="/img/play.svg" onClick={() => setState(true)}/>
        </RadioContainer>
      : <RadioContainerSecond>
          <PlayButton src="/img/pause.svg" onClick={() => setState(false)}/>
          <Video
            width="560"
            height="315"
            src="https://www.youtube.com/embed/21qNxnCS8WU?autoplay=1&controls=0"
            title="YouTube video player"
            frameborder="0"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
          />
        </RadioContainerSecond>
    

  return (
    <OuterCircle>
      <InnerCircle>
        { mainComponent }
      </InnerCircle>
    </OuterCircle>
  );
}
  • Related