React中如何用useState实现条件触发的文本显示?
问题描述
我是React新手,正在学习该框架。目前通过教程等资料,我已经实现了一个带有明暗模式的计算器。我想在右侧添加一个div,使其根据条件显示不同文本,例如:当计算结果超过9000时,显示“its over 9000!”等内容。我希望基于不同条件展示多条文本语句,但尝试过程中不断遇到undefined、state为const等错误。请问使用useState实现该功能的最佳方法是什么?
现有代码
//imports export const actionsPossible = { add_: "add", operation_: "operation", clear_: "clear", delete_: "delete", equal_: "equal", } function reducer(state, { type, payload }) { switch (type) { case actionsPossible.add_: //add if (state.overwrite) { return { ...state, currentOperand: payload.digit, overwrite: false, } } if (payload.digit === "." && state.currentOperand == null) { return state } if (payload.digit === "0" && state.currentOperand === "0") { return state } if (payload.digit === "." && state.currentOperand.includes(".")) { return state } return { ...state, currentOperand: `${state.currentOperand || ""}${payload.digit}`, } case actionsPossible.clear_: //clear { return {} } case actionsPossible.operation_: //choosing operation if (state.currentOperand == null && state.previousOperand == null) { return state } if (state.currentOperand == null) { return { ...state, Operation: payload.Operation, } } if (state.previousOperand == null) { return { ...state, Operation: payload.Operation, previousOperand: state.currentOperand, currentOperand: null, } } return { ...state, previousOperand: evaluate(state), currentOperand: null, operation_: payload.operation_, } case actionsPossible.equal_: //equal { if (state.Operation == null || state.currentOperand == null || state.previousOperand == null) { return state } return { ...state, overwrite: true, previousOperand: null, currentOperand: evaluate(state), Operation: null, } } case actionsPossible.delete_: //delete { if (state.overwrite) { return { ...state, overwrite: false, currentOperand: null } } if (state.currentOperand == null) { return state } if (state.currentOperand.length === 1) { return { ...state, currentOperand: null } } return { ...state, currentOperand: state.currentOperand.slice(0, -1) } } default: return state //default case } } function evaluate({ currentOperand, previousOperand, Operation }) { const previous = parseFloat(previousOperand) const current = parseFloat(currentOperand) if (isNaN(previous) || isNaN(current)) return "" let computation = "" switch (Operation) { case "+": computation = previous + current break case "-": computation = previous - current break case "*": computation = previous * current break case "÷": computation = previous / current break default: return } return computation.toString() } }) function formatOperand(operand) { // format so 1000 can be 1,000 } function App() { //const [Trivia, setTrivia] = useState("") const [theme, setTheme] = useState("light") const [{ currentOperand, previousOperand, Operation }, dispatch] = useReducer(reducer, {}) const toggleTheme = () => { setTheme((curr) => (curr === "light" ? "dark" : "light")) } return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> <div id={theme}> <div className="calculator-grid"> <div className="output"> <div className="previous-operand">{formatOperand(previousOperand)} {Operation}</div> <div className="current-operand">{formatOperand(currentOperand)}</div> </div> <button className="span-two" onClick={() => dispatch({ type: actionsPossible.clear_ })}>AC</button> <button onClick={() => dispatch({ type: actionsPossible.delete_ })}>DEL</button> <OperationButton Operation="÷" dispatch={dispatch} /> <DigitButton digit="1" dispatch={dispatch} /> <DigitButton digit="2" dispatch={dispatch} /> <DigitButton digit="3" dispatch={dispatch} /> <OperationButton Operation="*" dispatch={dispatch} /> <DigitButton digit="4" dispatch={dispatch} /> <DigitButton digit="5" dispatch={dispatch} /> <DigitButton digit="6" dispatch={dispatch} /> <OperationButton Operation="+" dispatch={dispatch} /> <DigitButton digit="7" dispatch={dispatch} /> <DigitButton digit="8" dispatch={dispatch} /> <DigitButton digit="9" dispatch={dispatch} /> <OperationButton Operation="-" dispatch={dispatch} /> <DigitButton digit="." dispatch={dispatch} /> <DigitButton digit="0" dispatch={dispatch} /> <button className="span-two" onClick={() => dispatch({ type: actionsPossible.equal_ })}>=</button> {/*----------------------------------TOGGLE BTN--------------------------------*/} //toggle button code, not important {/*----------------------------------TRIVIA--------------------------------*/} <div className="count"> <h1>Random Trivia</h1> <h4>{Trivia}</h4> {/* <h4>{Trivia2}</h4> */} {/* <h4>{Trivia3}</h4> */} {/* <h4>{Trivia4}</h4> */} </div> </div> </ThemeContext.Provider> ); } export default App;
解决方案
核心思路
其实不需要额外的useState存储提示文本,直接基于当前计算结果(currentOperand)动态判断即可。这样能彻底避免状态不同步、undefined这类问题,因为所有判断都依赖最新的reducer状态。
具体实现步骤
- 删掉注释掉的
Trivia相关useState代码,不用手动维护这个状态。 - 写一个函数,根据
currentOperand的值返回对应提示文本,注意处理空值和非数字的情况。 - 把函数的返回值直接渲染到右侧的
div里。
修改后的关键代码
在App组件中添加如下逻辑:
function App() { const [theme, setTheme] = useState("light") const [{ currentOperand, previousOperand, Operation }, dispatch] = useReducer(reducer, {}) const toggleTheme = () => { setTheme((curr) => (curr === "light" ? "dark" : "light")) } // 根据计算结果生成提示文本 const getTriviaText = () => { // 没有结果时显示默认提示 if (!currentOperand) return "等待计算结果..." // 转成数字,判断是否有效 const result = parseFloat(currentOperand) if (isNaN(result)) return "" // 按条件返回不同文本 if (result > 9000) return "its over 9000!" if (result === 42) return "宇宙终极答案!" if (result < 0) return "结果是负数哦~" if (result % 2 === 0) return "结果是偶数!" // 可以继续添加任意多的条件 return "计算完成!" } return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> <div id={theme}> <div className="calculator-grid"> {/* 原有计算器按钮、输出区域代码保持不变 */} {/* 右侧提示区域 */} <div className="count"> <h1>Random Trivia</h1> <h4>{getTriviaText()}</h4> </div> </div> </div> </ThemeContext.Provider> ); }
为什么这个方案更合适?
- 无状态不同步问题:提示文本完全跟着计算结果走,不需要手动更新状态,自然不会出现状态滞后或
undefined的情况。 - 代码更简洁:把判断逻辑封装成函数,可读性强,后续加新条件直接在函数里加就行。
- 符合React数据流:提示文本是派生状态,不需要额外的
useState,完全依赖现有reducer管理的状态。
常见错误规避
undefined错误:先判断currentOperand是否为空,转数字后检查isNaN,避免无效值导致报错。- 修改const state错误:因为没有用额外的
useState,只是基于现有状态计算,所以不会出现修改const变量的问题。
内容的提问来源于stack exchange,提问作者HyperOni
相关产品推荐
相关产品推荐

