React useEffect不触发props传入函数,提交无法生成新随机数
问题描述
将生成两个随机数及其求和结果的函数作为props传入复用组件MainInput,首次加载功能正常,但提交时无法生成新的数字和结果。同时出现useEffect依赖缺失警告:
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.
添加calculation作为依赖后问题仍未解决,未复用代码前功能完全正常。
相关代码
复用组件 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;
解决方案
问题根源
- 父组件随机数只生成一次:
AdditionMain中直接调用generateNumbersAndResults()赋值给calculation,仅在组件首次挂载时执行一次,后续重新渲染不会生成新的随机数。 - 状态管理逻辑错位:子组件
MainInput试图通过自身状态触发新数字生成,但新数字的生成权在父组件,子组件的状态变化无法驱动父组件重新生成随机数。
修复步骤
1. 改造父组件AdditionMain
用useState管理随机数状态,新增生成新随机数的函数并传递给子组件:
import React, { useState } from "react"; import MainInput from "../components/MainInput"; import { generateNumbersAndResults } from "../MainArithmetics"; const AdditionMain = () => { const operation = '+' // 用useState管理随机数状态,初始化时生成第一组数字 const [calculation, setCalculation] = useState(generateNumbersAndResults()); // 生成新随机数的函数 const generateNewCalculation = () => { setCalculation(generateNumbersAndResults()); }; return ( <> <MainInput operation={operation} calculation={calculation} generateNewCalculation={generateNewCalculation} // 传递给子组件 /> </> ); }; export default AdditionMain;
2. 简化子组件MainInput
移除冗余状态,直接使用父组件传入的calculation,调用父组件函数生成新数字,修复useEffect依赖问题:
const correctAnswer = <Typography>Correct!</Typography>; const wrongAnswer = <Typography>Wrong!</Typography>; const enterAnswer = <Typography>Enter your answer!</Typography>; const MainInput = ({operation, calculation, generateNewCalculation}) => { const [enteredValue, setEnteredValue] = useState(""); const [correctValue, setCorrectValue] = useState(false); const [isIncorrect, setIsIncorrect] = useState(false); const [haveToEnterAnswer, setHaveToEnterAnswer] = useState(false); // 当父组件传来的calculation更新时,重置输入状态 useEffect(() => { setEnteredValue(""); setCorrectValue(false); setIsIncorrect(false); setHaveToEnterAnswer(false); }, [calculation]); const submitHandler = () => { if (correctValue) { // 调用父组件函数生成新数字 generateNewCalculation(); return; } 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}> {calculation.number1} {operation} {calculation.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;
关键说明
- 将随机数生成逻辑放在父组件并通过状态管理,确保每次需要新数字时能触发组件重新渲染,生成全新的随机数。
- 子组件不再维护冗余状态,直接使用父组件传入的数据和方法,既简化了逻辑,也彻底解决了
useEffect的依赖警告问题。
内容的提问来源于stack exchange,提问作者Süleyman Eminbəyli
相关产品推荐
相关产品推荐

