Apologies if this is a long post. I have been trying to make sense of this for the past few days and yet I have not been able to. I would appreciate any help. Below, in my main component, I have a series of questions. The answer to each is a simple yes or no (initialized as null) that will be saved by Zustand. When the user goes to the next question, I am keeping the previous answers since the fields are controlled. However, if the user clicks the Back button in <PageNav/>
on any card, I want to reset that specific card's answer back to null. My intuition in the custom hook was to reset to null using the return
cleanup function of the useEffect
as you see below. However, it is not working.
Main component:
export default const Test = () => {
const questions: Record<number, ReactElement> = {
1: <Question1 />,
2: <Question2 />,
3: <Question3 />,
4: <Question4 />,
5: <Question5 />,
};
// Set the page navigation state
useEffect(() => {
nav.setTotalPages(Object.keys(display).length);
return () => {
nav.setTotalPages(0);
};
}, []);
return (
<>
{display[nav.page]}
<PageNav />
</>
);
};
Here is the question component:
export default const Question1 = () => {
const { value, handleChange } = useQuiz("question1");
return (
<RadioYesNo
question="Question 1"
lable={[
"Yes",
"No",
]}
value={value}
handleChange={handleChange}
/>
);
};
Custom component for each question:
export default const RadioYesNo = ({
question,
lable,
value,
handleChange,
}) => {
return (
<Stack spacing={4} alignItems="center">
<Typography>{question}</Typography>
<RadioGroup name="question" value={value} onChange={handleChange}>
<FormControlLabel value="y" control={<Radio />} label={lable[0]} />
<FormControlLabel value="n" control={<Radio />} label={lable[1]} />
</RadioGroup>
</Stack>
);
};
Custom hook to implement the useEffect for each question:
export default const useQuiz = (storeProperty: keyof EligibilitySlice) => {
// Page navigation states:
const resetPageState = useStore.use.resetPageState();
const isNextClicked = useStore.use.isNextClicked();
const isBackClicked = useStore.use.isBackClicked();
const storeValue = useStore.use[storeProperty]();
const [value, setValue] = useState(
storeValue === "y" ? "y" : storeValue === "n" ? "n" : ""
);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue((event.target as HTMLInputElement).value);
};
useEffect(() => {
resetPageState(); // Resets isBackClicked & isNextClicked to false
console.log("page state is reset");
useStore.setState({
[storeProperty]: value === "y" ? "y" : value === "n" ? "n" : null,
});
useStore.setState({ isNextActive: !!value });
return () => {
console.log("unmounting");
if (isBackClicked) {
useStore.setState({
[storeProperty]: null,
});
console.log("property ", storeProperty, " was reset to null");
}
useStore.setState({ isNextActive: false });
};
}, [value, isBackClicked, isNextClicked]);
return { value, handleChange };
};
and here is the PageNav component that houses the Next and Back buttons, which update the isBackClicked and isNextClicked states in Zustand store:
const PageNav = () => {
const nav = {
page: useStore.use.page(),
totalPages: useStore.use.totalPages(),
prevPage: useStore.use.prevPage(),
nextPage: useStore.use.nextPage(),
isBackActive: useStore.use.isBackActive(),
isNextActive: useStore.use.isNextActive(),
};
return (
<Stack spacing={4} alignItems="center">
<Typography px={6}>{`${nav.page} of ${nav.totalPages}`}</Typography>
<Stack direction="row" spacing={4}>
<Button
variant="contained"
onClick={() => {
nav.prevPage();
}}
disabled={nav.page === 1 || !nav.isBackActive}
>
Back
</Button>
<Button
variant="contained"
onClick={() => {
nav.nextPage();
}}
disabled={nav.page === nav.totalPages || !nav.isNextActive}
>
Next
</Button>
</Stack>
</Stack>
);
};
export default PageNav;