我正在try 在Reaction中创建一个简单的常量营养素计算器,它有多个输入字段,需要用户输入数值才能进行一些计算.当前的问题是,如果用户最后一次填写"gram"输入域,则计算将无法工作,除非他更改其他每个域.每次计算都使用gramsEaten变量,并且总是需要首先填充该变量才能正常工作.

const [gramsEaten, setGramsEaten] = useState(0);
const [totalKcal, setTotalKcal] = useState(0);
const [totalCarbs, setTotalCarbs] = useState(0);
const [totalFats, setTotalFats] = useState(0);
const [totalProtein, setTotalProtein] = useState(0);

let handleGramsEatenChange = (e) => {
    let grams = e.target.value;
    setGramsEaten(grams);
}

let handleKcalChange = (e) => {
    let kcal = e.target.value;
    setTotalKcal((gramsEaten * kcal) / 100);
}

let handleCarbsChange = (e) => {
    let carbs = e.target.value;
    setTotalCarbs((gramsEaten * carbs) / 100);
}

let handleFatsChange = (e) => {
    let fats = e.target.value;
    setTotalFats((gramsEaten * fats) / 100);
}

let handleProteinChange = (e) => {
    let protein = e.target.value;
    setTotalProtein((gramsEaten * protein) / 100);
}

以及输入字段结果的顺序(&A;):

<input type="number" min="0" onChange={handleKcalChange}/>
<input type="number" min="0" onChange={handleCarbsChange}/>
<input type="number" min="0" onChange={handleFatsChange}/>
<input type="number" min="0" onChange={handleProteinChange}/>

<label>How many grams have you consumed?</label>
<input type="number" min="0" onChange={handleGramsEatenChange}/>

<table>
    <tbody>
    <tr>
        <th>Total calories</th>
        <td>{Math.ceil(totalKcal)}</td>
    </tr>
    <tr>
        <th>Total carbohydrates</th>
        <td>{Math.ceil(totalCarbs)}</td>
    </tr>
    <tr>
        <th>Total fats</th>
        <td>{Math.ceil(totalFats)}</td>
    </tr>
    <tr>
        <th>Total protein</th>
        <td>{Math.ceil(totalProtein)}</td>
    </tr>
    </tbody>
</table>

推荐答案

解决这个问题的办法可能是只存储输入的状态.不要先计算总数.

const [gramsEaten, setGramsEaten] = useState(0);
const [kcal, setKcal] = useState(0);
const [carbs, setCarbs] = useState(0);
const [fats, setFats] = useState(0);
const [protein, setProtein] = useState(0);

let handleGramsEatenChange = (e) => {
    setGramsEaten(e.target.value);
}

let handleKcalChange = (e) => {
    setKcal(e.target.value);
}

let handleCarbsChange = (e) => {
    setCarbs(e.target.value);
}

let handleFatsChange = (e) => {
    setFats(e.target.value);
}

let handleProteinChange = (e) => {
    setProtein(e.target.value)
}

然后,在视图中,您可以在那里进行计算.当用户输入一个字符串或一些无效的非数字时,值可能会显示NaN,因此您可以对输入进行验证.在该视图中,如果还没有输入计算所需的构成值,则还可以使用条件条件来隐藏该值,如"kcal==unfined&;&;gram sEten!==unfined&;&;Math.ceil((kcal*gram sEten)/100)"所示.

<input type="number" min="0" onChange={handleKcalChange}/>
<input type="number" min="0" onChange={handleCarbsChange}/>
<input type="number" min="0" onChange={handleFatsChange}/>
<input type="number" min="0" onChange={handleProteinChange}/>

<label>How many grams have you consumed?</label>
<input type="number" min="0" onChange={handleGramsEatenChange}/>

<table>
    <tbody>
    <tr>
        <th>Total calories</th>
        <td>{kcal == undefined && gramsEaten !== undefined && Math.ceil((kcal*gramsEaten)/100)}</td>
    </tr>
    <tr>
        <th>Total carbohydrates</th>
        <td>{Math.ceil(carbs*gramsEaten)/100}</td>
    </tr>
    <tr>
        <th>Total fats</th>
        <td>{Math.ceil(fats*gramsEaten/100)}</td>
    </tr>
    <tr>
        <th>Total protein</th>
        <td>{Math.ceil(protein*gramsEaten)/100}</td>
    </tr>
    </tbody>
</table>

建议您将所有相关状态存储在一个对象中,而不是单独的useState.

const [macronutrientState, setMacronutrientState] = useState({fats: undefined, carbs: undefined, gramsEaten: undefined, kcal: undefined})

const handleMacronutrientStateChange = (e) => {
    setMacronutrientState((prevMacronutrientState) => 
        ({...prevMacronutrientState, 
             [e.target.name]: e.target.value
         }
        )
    )
}

<input type="number" min="0" name="kcal" onChange={handleMacronutrientChange}/>
<input type="number" min="0" name="carbs" onChange={handleMacronutrientChange}/>
<input type="number" min="0" name="fats" onChange={handleMacronutrientChange}/>
<input type="number" min="0" name="protein" onChange={handleMacronutrientChange}/>

<label>How many grams have you consumed?</label>
<input type="number" min="0" name="gramsEaten" onChange={handleMacronutrientChange}/>

<table>
    <tbody>
    <tr>
        <th>Total calories</th>
        <td>{Math.ceil((macronutrientState.kcal*macronutrientState.gramsEaten)/100))}</td>
    </tr>
    <tr>
        <th>Total carbohydrates</th>
        <td>{Math.ceil((macronutrientState.carbs*macronutrientState.gramsEaten)/100))}</td>
    </tr>
    <tr>
        <th>Total fats</th>
        <td>{Math.ceil((macronutrientState.fats*macronutrientState.gramsEaten)/100))}</td>
    </tr>
    <tr>
        <th>Total protein</th>
        <td>{Math.ceil((macronutrientState.protein*macronutrientState.gramsEaten)/100))}</td>
    </tr>
    </tbody>
</table>

这是一个很好的实践,因为它可以帮助您组织状态,并重用相同的函数handleMacronutrientStateChange,该函数根据输入中给出的名称设置状态.

Reactjs相关问答推荐

在此上下文中如何在缓冲(隐藏)视频和渲染视频之间切换?

React onKeyUp不一致地使用快速Shift+键按压

在react中向数组状态添加值时出错

下拉Tailwind CSS菜单与怪异beviour

在Reaction中管理多个状态

在构建或部署Reaction应用程序时出错

Gitlab CI和VITE环境变量出现问题

如何在中间件中获取 nextAuth 会话

如何修复ReferenceError:在构建过程中未定义导航器

无法使用 Suspense 和 Await 获取数据

如何在 React Hook Form 中使用嵌套对象处理错误验证消息

在一个事件处理程序中进行多次调度是个好主意吗?

获取更多数据后更新 DOM,而不刷新 React.js 中的页面

如何在 React 中停止嵌套 Link 和 Button 组件的事件传播?

臭名昭著的测试未包含在 act(...) 中

如何在对话素材ui中设置边框半径?

ReactJS:useMemo 钩子修复了我的无限重新渲染问题而不是 useEffect

具有自动完成功能的 Formik material ui 无法按预期工作

为什么我不能使用 formik 更改此嵌套对象中的值

为什么这两个 div 的渲染方式不同?