React使用useReducer提升状态时触发跨组件更新错误的问询
React useReducer状态提升时报错:Cannot update a component while rendering another component
我正在学习useReducer函数,尝试用它构建一个基于React的测验选择界面,目标是将组件内的状态更新后提升至主App组件,供其他模块使用。
遇到的问题
- 将reducer放在组件外部时,无法完成状态设置;
- 将reducer放在组件内部时,状态能成功提升到App组件,但控制台会抛出以下错误:
Cannot update a component (App) while rendering a different component (GetQuestionDATA)
GetQuestionDATA组件代码
import { useReducer } from "react"; import React from "react"; import Select from "react-select"; export function GetQuestionDATA({ setAPIParams }) { // USE REDUCER to get our various Data from state shown on screen. // set initial state const initialState = { amount: "10", category: "", difficulty: "", type: "", }; // set the Amount, with reducer const [state, dispatch] = useReducer(reducer, initialState); function reducer(state, action) { // we don't tend to use ifs or terniary in reducers instead we look at using the switch keyword, which takes our action type and creates a case for each type. switch (action.type) { case "setAmount": return { ...state, amount: action.payload }; case "setCategory": return { ...state, category: action.payload }; case "setDifficulty": return { ...state, difficulty: action.payload }; case "setType": return { ...state, type: action.payload }; case "start": return setAPIParams(state); default: throw new Error("Unknown action"); } } const defineAmount = function (e) { dispatch({ type: "setAmount", payload: Number(e.target.value) }); }; const defineCategory = function (e) { dispatch({ type: "setCategory", payload: e.value }); }; const defineDifficulty = function (e) { dispatch({ type: "setDifficulty", payload: e.value }); }; const defineType = function (e) { dispatch({ type: "setType", payload: e.value }); }; const start = function () { dispatch({ type: "start" }); }; // set state based on choices (dispatch + action) // Buncle the state into an object (reducer) //----- jsx options -----// // category const category_options = [ { value: "9", label: "General Knowledge" }, { value: "10", label: "Entertainment: Books" }, { value: "11", label: "Entertainment: Film" }, { value: "12", label: "Entertainment: Music" }, { value: "13", label: "Entertainment: Musical & Theaters" }, { value: "14", label: "Entertainment: Television" }, { value: "15", label: "Entertainment: Video Games" }, { value: "16", label: "Entertainment: Board Games" }, { value: "17", label: "Science & Nature" }, { value: "18", label: "Science: Computers" }, { value: "19", label: "Science: Mathmatics" }, { value: "20", label: "Mythology" }, { value: "21", label: "Sports" }, { value: "22", label: "Geography" }, { value: "23", label: "History" }, { value: "24", label: "Politics" }, { value: "25", label: "Art" }, { value: "26", label: "Celebrities" }, { value: "27", label: "Animals" }, ]; // difficulty const difficulty_options = [ { value: "easy", label: "Easy" }, { value: "medium", label: "Medium" }, { value: "hard", label: "Hard" }, ]; // type const type_options = [ { value: "multiple", label: "Multiple Choice" }, { value: "boolean", label: "True / False" }, ]; // encoding (hidden) return ( <div className="quiz-selection"> <p>Number Of Questions</p> <div className="quiz-buttons"> <span> <button value="10" onClick={defineAmount}> 10 </button> </span> <span> <button value="20" onClick={defineAmount}> 20 </button> </span> <span> <button value="30" onClick={defineAmount}> 30 </button> </span> <span> <button value="40" onClick={defineAmount}> 40 </button> </span> <span> <button value="50" onClick={defineAmount}> 50 </button> </span> </div> <div className="select"> <p className="cat-header">Category</p> <Select onChange={defineCategory} options={category_options} /> <p className="cat-header">Difficulty</p> <Select onChange={defineDifficulty} options={difficulty_options} /> <p className="cat-header">Type</p> <Select onChange={defineType} options={type_options} /> </div> <div> <button className="quiz-buttons" onClick={start}> Start </button> </div> </div> ); }
补充说明
我知道Context和Redux可以解决这类状态共享问题,但目前还没学到相关内容,希望用已掌握的useReducer+状态提升的方式修复。
尝试过的方法:
- 用useEffect包裹相关逻辑,但控制台提示不能在回调中包裹reducer;
- 将reducer移进/移出组件,结果要么还是出现相同报错(状态能正常提升),要么完全无法通过setState提升状态。
问题解决
编辑:已解决问题。解决方案是在组件内创建一个独立状态,让reducer负责更新这个组件内部状态,然后通过useEffect监听该状态的变化,在回调中调用App组件传递过来的setAPIParams来完成状态提升。
内容的提问来源于stack exchange,提问作者user21629409
相关产品推荐
相关产品推荐

