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

React3文件拆分:useState跨组件传值实现BMI计算

问题根源

React 遵循单向数据流规则,组件内部通过useState维护的状态是私有状态,父组件无法直接读取子组件的内部状态。你当前把身高、体重、年龄、性别这些输入值存在Calculator.js内部,父组件BMI.js点击Calculate按钮时自然拿不到输入值,也没法把计算结果传给Result.js渲染。

推荐实现方案:状态提升

把多个组件共用的状态、关联计算逻辑统一提升到最近的公共父组件(也就是你的BMI.js)中维护,子组件只通过props接收需要的数据、通过回调通知父组件更新状态即可,这是React官方推荐的跨组件状态共享方案,适配你当前的组件拆分结构,改造成本最低。

具体实现步骤

1. 改造父组件 BMI.js

把页面状态、输入数据状态、BMI计算结果状态、计算逻辑、页面切换逻辑全部放在父组件维护,给子组件传对应的props:

import { useState } from 'react';
import Calculator from './Calculator';
import Result from './Result';

export default function BMI() {
  // 页面切换状态:0=计算页 1=结果页
  const [page, setPage] = useState(0);
  // 提升到父组件的用户输入状态
  const [userInput, setUserInput] = useState({
    height: '',
    weight: '',
    age: '',
    gender: ''
  });
  // BMI计算结果状态
  const [bmiResult, setBmiResult] = useState({
    score: 0,
    level: ''
  });

  // 点击Calculate触发的计算+跳转逻辑
  const handleCalculate = () => {
    // 基础输入校验
    if (!userInput.height || !userInput.weight) {
      alert('请先输入有效的身高、体重值');
      return;
    }
    // BMI标准计算公式:体重(kg) / 身高(m)的平方
    const heightM = Number(userInput.height) / 100;
    const score = Number((Number(userInput.weight) / (heightM * heightM)).toFixed(1));
    
    // 匹配健康等级
    let level = '';
    if (score < 18.5) level = '偏瘦,建议适当补充营养';
    else if (score < 24) level = '正常,继续保持良好作息';
    else if (score < 28) level = '偏胖,建议增加运动量';
    else level = '肥胖,建议咨询专业医生调整饮食作息';

    setBmiResult({ score, level });
    setPage(1);
  };

  const handleBack = () => {
    setPage(0);
  };

  return (
    <div className="bmi-wrapper">
      {page === 0 ? (
        <>
          <Calculator 
            userInput={userInput} 
            updateInput={setUserInput} 
          />
          <button className="calc-btn" onClick={handleCalculate}>Calculate</button>
        </>
      ) : (
        <>
          <Result bmiResult={bmiResult} />
          <button className="back-btn" onClick={handleBack}>Back</button>
        </>
      )}
    </div>
  );
}

2. 改造输入子组件 Calculator.js

删除组件内部原有的身高、体重、年龄、性别相关useState,所有输入值从props读取,输入变化时调用父组件传的更新方法即可:

export default function Calculator({ userInput, updateInput }) {
  // 统一处理输入更新
  const handleValueChange = (field, value) => {
    updateInput(prev => ({
      ...prev,
      [field]: value
    }));
  };

  return (
    <div className="calculator-panel">
      <div className="gender-group">
        <button
          className={userInput.gender === 'male' ? 'gender-btn active' : 'gender-btn'}
          onClick={() => handleValueChange('gender', 'male')}
        >
          男性
        </button>
        <button
          className={userInput.gender === 'female' ? 'gender-btn active' : 'gender-btn'}
          onClick={() => handleValueChange('gender', 'female')}
        >
          女性
        </button>
      </div>

      <div className="input-item">
        <label>身高(cm)</label>
        <input
          type="number"
          value={userInput.height}
          onChange={(e) => handleValueChange('height', e.target.value)}
        />
      </div>
      <div className="input-item">
        <label>体重(kg)</label>
        <input
          type="number"
          value={userInput.weight}
          onChange={(e) => handleValueChange('weight', e.target.value)}
        />
      </div>
      <div className="input-item">
        <label>年龄</label>
        <input
          type="number"
          value={userInput.age}
          onChange={(e) => handleValueChange('age', e.target.value)}
        />
      </div>
    </div>
  );
}

3. 改造结果子组件 Result.js

删除组件内部原有的bmiScore、bmiDesc状态,直接读取父组件传入的计算结果渲染:

export default function Result({ bmiResult }) {
  return (
    <div className="result-panel">
      <div className="score-display">{bmiResult.score}</div>
      <div className="level-desc">{bmiResult.level}</div>
    </div>
  );
}
其他可选方案说明
  • 可以通过useImperativeHandle配合ref把子组件的输入值暴露给父组件,但这种方式违背React单向数据流的设计原则,后续功能迭代时状态溯源难度高,不推荐在这种场景使用
  • 如果后续组件嵌套层级变深、跨组件共享的状态变多,可以引入Context或者状态管理库,但你当前的组件结构用状态提升是最简单、维护成本最低的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 02:57:09