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>
);
}