【发布时间】:2023-03-09 18:08:01
【问题描述】:
我正在尝试在 react 中构建一个迷你项目,它是一个 BMI 跟踪器,用户输入他的体重和身高,然后程序计算 BMI 并且每当应用程序从用户那里收到数据(身高和体重)时,它然后表示结果和用户在图表中输入该数据的日期。为此,我制作了三个组件,第一个是 InputContainer 组件,在其中执行计算。
import React, { useState, useRef, useEffect } from 'react';
import Graph from '../Graph/Graph';
import Logs from '../Logs/logs';
import './InputContainer.scss';
let date;
let currentDate;
let dates = []
let bmiResults = []
let dataLog = [];
export default function InputContainer() {
const [result, setBmiResult] = useState('');
const [height, setHeight] = useState('');
const [weight, setWeight] = useState('');
const [bmiAxis,setBmiAxis] = useState('');
const [dateAxis,setDateAxis] = useState('');
const calculateButton = useRef(null);
const firstUpdate = useRef(true);
useEffect(() => {
date = new Date();
currentDate = `${date.getDate()}/${date.getMonth()}/${date.getFullYear()}`
calculateButton.current.disabled = isNaN(parseFloat(height) && parseFloat(weight)) ? true : false;
}, [height, weight]);
useEffect(() => {
if (firstUpdate.current) {
firstUpdate.current = false;
return
}
let dataLogElement = <div className="test">
<div className="bmi-and-date">
<p className="bmi">
BMI: {result}
</p>
<p className="date">
Date: {currentDate}
</p>
</div>
<div className="height-and-weight">
<p className="height">
Height: {height}
</p>
<p className="weight">
weight: {weight}
</p>
</div>
</div>;
dataLog.push(dataLogElement);
dates.push(currentDate);
bmiResults.push(result);
setBmiAxis(bmiResults);
setDateAxis(dates);
}, [result])
const calculate = () => {
let bmi = (parseFloat(weight) / parseFloat(height) ** 2).toFixed(2)
setBmiResult(parseFloat(bmi))
}
return (
<>
<div className='input-container'>
<h1>BMI Tracker</h1>
<div className="input">
<div className="height">
<h3>Enter Your Height in CM</h3>
<input type="number" onChange={(e) => {
setHeight(e.target.value)
}} value={height} />
</div>
<div className="weight">
<h3>Enter Your Weight in Kg</h3>
<input type="number" onChange={(e) => {
setWeight(e.target.value)
}} />
</div>
</div>
<button className='calculate' onClick={calculate} ref={calculateButton}>Calculate</button>
</div>
<Graph bmi={result} date={currentDate} dates={dateAxis} results={bmiAxis} />
<Logs element = {dataLog}/>
</>
)
}
第二个组件是Graph 组件,它从 props 接收用户的数据,然后将其显示在图表中:
import React from 'react'
import { Line } from 'react-chartjs-2';
import './Graph.scss'
export default function Graph(props) {
const data = {
labels: props.dates,
datasets: [
{
label: 'BMI',
data: props.results,
fill: 'origin',
backgroundColor: '#16a5e1',
pointBackgroundColor: '#16a5e1',
pointBorderColor: 'blue',
pointRadius: '4'
},
],
};
const options = {
tension: 0.4,
scales: {
y: {
ticks: {
color: 'white'
},
beginAtZero: true
},
x: {
ticks: {
color: 'white'
},
}
}
};
return (
<div className='graph-container'>
<Line data={data} options={options} />
</div>
)
}
然后是第三个组件,即Logs 组件,它显示
页面按钮上每个用户提交的详细信息
import React from 'react'
import './logs.scss'
export default function Logs(props) {
return (
<div className='logs-container'>
{props.element}
</div>
)
}
启动应用程序后,我输入体重和身高,然后单击calculate 按钮,数据成功绘制到图表中,其相应的详细信息记录在页面底部,这正是我想要,但问题是用户输入的数据仅在第一次输入时成功显示,当我第二次输入数据时,在后台正确完成计算并计算第二次输入的结果,但没有任何变化在屏幕上,我只能看到第一个条目的结果,然后一旦我开始为第三个条目输入数据,我会得到第一个的结果以及我之前输入的第二个条目显示在屏幕上,只有结果当我开始为下一个条目输入数据时显示,而不是在单击 calculate 按钮后立即显示。
这是我想要实现的示例:
如果你想在你的机器上测试它,这里是一个 repo 的链接: https://github.com/Marouane328/Bmi-tracker
【问题讨论】:
-
一些注意事项: (1) 不要将标记放入状态。 (2) 不要仅仅使用 refs 来设置按钮的属性;只需使用道具。 (3) BMI 结果应该是一个计算值,而不是状态的一部分,因为它不是用户可编辑的。 (4) 应该没有全局的
dates/bmiResults/...变量;任何更改都不会被任何东西跟踪,也不会重新渲染。 -
@AKX 感谢您的注释,您说我不应该使用 refs 来设置按钮的属性,我能做些什么呢?我将 BMI 结果设置为状态的一部分,因为只有在计算结果时才会更新状态,因此重新渲染
-
<button disabled={isNaN(parseFloat(height) && parseFloat(weight))} /> -
而且您不需要将 BMI 置于状态,因为身高和体重已经处于状态。如果身高和体重发生变化,组件会重新渲染,您可以根据这些计算组件内的 BMI。
-
@AKX 谢谢,我没注意,谢谢!
标签: javascript reactjs