confusing useEffect situation

84 Views Asked by At

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;
0

There are 0 best solutions below