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

React中useEffect未更新按钮数组:BMI计算器按钮样式不切换

BMI计算器按钮样式不更新问题修复方案

问题根源

你的代码存在两个关键问题导致按钮样式无法随BMI值更新:

  1. useEffect使用错误:
    • 给useEffect的回调函数添加了(answer)参数,这会覆盖组件内计算的BMI值,导致逻辑判断用的是无效变量
    • 未设置依赖数组,要么useEffect只在初始渲染时执行一次,要么因为setButtons触发重渲染而陷入无限循环,无法响应BMI值变化
  2. 未处理BMI无效情况:当身高为0时,计算出的answer会变成Infinity,此时样式逻辑会错误触发最后一个按钮的样式

修复方案(基于原有代码修改)

修改Answer.js中的useEffect部分,调整如下:

import React, { useEffect, useState } from "react";
import "../stylesheets/answer.css";

export default function Answer(props) {
  const [buttons, setButtons] = useState([
    "btn-primary",
    "btn-primary",
    "btn-primary",
    "btn-primary",
    "btn-primary",
    "btn-primary",
  ]);

  let height = parseFloat(props.heightVal);
  let weight = parseFloat(props.weightVal);
  let answer = weight / Math.pow(height, 2);

  // 修正useEffect写法
  useEffect(() => {
    let newButtons = [
      "btn-primary",
      "btn-primary",
      "btn-primary",
      "btn-primary",
      "btn-primary",
      "btn-primary",
    ];

    // 先判断BMI值是否有效
    if (!isNaN(answer) && isFinite(answer)) {
      if (answer < 18.5) {
        newButtons[0] = "btn-danger";
      } else if (answer >= 18.5 && answer < 25) {
        newButtons[1] = "btn-danger";
      } else if (answer >= 25 && answer < 30) {
        newButtons[2] = "btn-danger";
      } else if (answer >= 30 && answer < 35) {
        newButtons[3] = "btn-danger";
      } else if (answer >= 35 && answer < 40) {
        newButtons[4] = "btn-danger";
      } else if (answer >= 40) {
        newButtons[5] = "btn-danger";
      }
    }

    setButtons(newButtons);
  }, [answer]); // 添加依赖数组,仅当answer变化时执行

  return (
    <div className="container d-flex flex-column align-items-center justify-content-center text-center">
      <p className="align-self-center h1 m-5">
        Your BMI is:{" "}
        {isNaN(answer) || !isFinite(answer) ? "Not measured" : answer.toFixed(2)}
      </p>

      <div className="btn-group d-flex flex-row">
        <button className={"btn " + buttons[0]}> Underweight</button>
        <button className={"btn " + buttons[1]}> Normal</button>
        <button className={"btn " + buttons[2]}> Overweight</button>
        <button className={"btn " + buttons[3]}>Class I obesity</button>
        <button className={"btn " + buttons[4]}>Class II obesity</button>
        <button className={"btn " + buttons[5]}>Class III obesity</button>
      </div>
    </div>
  );
}

更简洁的优化方案(无需维护buttons状态)

可以直接根据BMI值动态计算每个按钮的类名,省去额外的状态管理:

import React from "react";
import "../stylesheets/answer.css";

export default function Answer(props) {
  let height = parseFloat(props.heightVal);
  let weight = parseFloat(props.weightVal);
  let answer = weight / Math.pow(height, 2);
  const isValidBMI = !isNaN(answer) && isFinite(answer);

  // 定义每个按钮对应的BMI范围
  const buttonConfigs = [
    { label: "Underweight", range: val => val < 18.5 },
    { label: "Normal", range: val => val >=18.5 && val <25 },
    { label: "Overweight", range: val => val >=25 && val <30 },
    { label: "Class I obesity", range: val => val >=30 && val <35 },
    { label: "Class II obesity", range: val => val >=35 && val <40 },
    { label: "Class III obesity", range: val => val >=40 },
  ];

  return (
    <div className="container d-flex flex-column align-items-center justify-content-center text-center">
      <p className="align-self-center h1 m-5">
        Your BMI is:{" "}
        {isValidBMI ? answer.toFixed(2) : "Not measured"}
      </p>

      <div className="btn-group d-flex flex-row">
        {buttonConfigs.map((config, index) => (
          <button 
            key={index}
            className={`btn ${isValidBMI && config.range(answer) ? "btn-danger" : "btn-primary"}`}
          >
            {config.label}
          </button>
        ))}
      </div>
    </div>
  );
}

内容的提问来源于stack exchange,提问作者Amirreza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 01:27:52