You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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状态。

具体实现步骤

  1. 删掉注释掉的Trivia相关useState代码,不用手动维护这个状态。
  2. 写一个函数,根据currentOperand的值返回对应提示文本,注意处理空值和非数字的情况。
  3. 把函数的返回值直接渲染到右侧的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:45:58