Home > Blockchain >  useEffect() doesn't re-call function that is given as a prop
useEffect() doesn't re-call function that is given as a prop

Time:01-16

I have a function that I am passing to my re-used component as a prop. This function generates and returns two random numbers and their addition result. Everything works on the first go, however, I can't figure out how to get it to generate new numbers and result on submit.

PS: I get a warning on useEffect dependency saying that

React Hook useEffect has a missing dependency: 'calculation'. Either include it or remove the dependency array. If 'setCalculatedNums' needs the current value of 'calculation', you can also switch to useReducer instead of useState and read 'calculation' in the reducer.

However, using calculation as the dependency doesn't work either.

PS: I had the code working perfectly initially before I decided it's a better practice to re-use pieces of code that don't need repetition. Just can't figure out how to get it done this way.

Here's the code:

the re-used component MainInput.js:

const correctAnswer = <Typography>Correct!</Typography>;
const wrongAnswer = <Typography>Wrong!</Typography>;
const enterAnswer = <Typography>Enter your answer!</Typography>;

const MainInput = ({operation, calculation}) => {
  const [enteredValue, setEnteredValue] = useState("");
  const [correctValue, setCorrectValue] = useState(false);
  const [calculatedNums, setCalculatedNums] = useState({});
  const [isIncorrect, setIsIncorrect] = useState(false);
  const [generateNewNumbers, setGenerateNewNumbers] = useState(false);
  const [haveToEnterAnswer, setHaveToEnterAnswer] = useState(false);

  useEffect(() => {
    
    setCalculatedNums(calculation);
    setGenerateNewNumbers(false);
    setCorrectValue(false);
    setEnteredValue("");
  }, [generateNewNumbers]);

  const submitHandler = () => {
    console.log(calculation.additionResult)
    if (correctValue) {
      
      setGenerateNewNumbers(true);
    }

    if ( enteredValue === calculation.additionResult) {
      setCorrectValue(true);
    } else if (enteredValue.length === 0) {
      setHaveToEnterAnswer(true);
    } else {
      setIsIncorrect(true);
    }
  };

  const inputValueHandler = (value) => {
    setIsIncorrect(false);
    setHaveToEnterAnswer(false);
    setEnteredValue(value);
  };

  const submitOrTryNewOne = () => {
    return correctValue ? "Try new one" : "Submit";
  };

  return (
    <>
      <Navbar />
      <Card
        sx={{
          marginTop: 2,
          height: 50,
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
        }}
      >
        <Typography></Typography>
      </Card>
      <Container component="main" maxWidth="xs">
        <Box
          sx={{
            marginTop: 8,
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
          }}
        >
          <Typography>Fill in the box to make the equation true.</Typography>
          <Typography fontSize={28}>
            {calculatedNums.number1} {operation} {calculatedNums.number2}{" "}
            =
          </Typography>
          <TextField
            inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
            type="number"
            name="sum"
            id="outlined-basic"
            label=""
            variant="outlined"
            onChange={(event) => {
              inputValueHandler(event.target.value);
            }}
            disabled={correctValue}
            value={enteredValue}
          ></TextField>
          {haveToEnterAnswer && enterAnswer}
          {correctValue && correctAnswer}
          {isIncorrect && wrongAnswer}

          <Button
            type="button"
            sx={{ marginTop: 1 }}
            onClick={() => submitHandler()}
            variant="outlined"
          >
            {isIncorrect ? "Try again!" : submitOrTryNewOne()}
          </Button>
        </Box>
      </Container>
    </>
  );
};

export default MainInput;

MainArithmetics.js

export const generateNumbersAndResults = () => {
  const randomNum1 = () => {
    return Math.floor(Math.random() * 50);
  };

  const randomNum2 = () => {
    return Math.floor(Math.random() * 50);
  };

  const number1 = randomNum1() || 0;
  const number2 = randomNum2() || 0;

  const additionResult = number1   number2 || 0;

 

 

  return {
    additionResult,
    number1,
    number2
  };
};

AdditionMain.js

import React from "react";
import MainInput from "../components/MainInput";
import { generateNumbersAndResults } from "../MainArithmetics";

const AdditionMain = () => {
  const operation = ' '
  const calculation = generateNumbersAndResults()

  return (
    <>
    {console.log(calculation)}
      <MainInput
        operation={operation}
        calculation={calculation}
        
      />
    </>
  );
};

export default AdditionMain;

CodePudding user response:

There is a lot of unneeded code, but the core issue is that calculation doesn't change. Once called, it's going to have a fixed set of numbers, so when you call:

setCalculatedNums(calculation);

It's just going to set the 'same' numbers again. If you want new numbers, you'll need to do something like:

setCalculatedNums(generateNumbersAndResults());

edit after comment

The core issue is that you are not passing a function, you are passing it's result. If you want to pass the function, instead of:

const calculation = generateNumbersAndResults();

you'll want:

const calculation = generateNumbersAndResults;

Then later on you make sure you call this function when you want to generate a new 'calculation'

setCalculatedNums(calculation());
  • Related