简体   繁体   English

设置状态后组件不会重新渲染

[英]Component doesn't re-render after I set state

I'm trying to build a mini project in react, it is a BMI tracker, the user enters his weight and height, then the program calculates the BMI and whenever the application receives data (height and weight) from the user it then represents the result and the date at which the user entered that data in a graph.我正在尝试在 React 中构建一个迷你项目,它是一个 BMI 跟踪器,用户输入他的体重和身高,然后程序计算 BMI,每当应用程序从用户那里收到数据(身高和体重)时,它就代表结果和用户在图表中输入该数据的日期。 For that, I made three components, the first is the InputContainer component inside of which the calculations are performed.为此,我制作了三个组件,第一个是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}/>
        </>
    )
}

the second component is the Graph component which receives the user's data from props and then displays it in a graph:第二个组件是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>
    )
}

Then the third component which is the Logs component, it displays the details of each user submission at the button of the page然后是第三个组件Logs组件,它在页面的按钮处显示每个用户提交的详细信息

import React from 'react'
import './logs.scss'
export default function Logs(props) {
    return (
        <div className='logs-container'>
            {props.element}
        </div>
    )
}

Once I start the app, I enter the weight and height then click the calculate button, the data gets plotted into the graph successfully and its corresponding details are logged at the bottom of the page, and this is exactly what I wanted, but the problem is that the data entered by the user gets displayed successfully only for the first entry, when I enter data a second time, calculations are done properly in the background and the results of the second entry are calculated, but nothing changes on the screen, and I can only see the results of the first entry, then once I start entering data for the third entry, I get the results of the first along with the second entry that I previously entered displayed on the screen, results only get displayed when I start entering data for the next entry and not immediately after clicking the calculate button.启动应用程序后,我输入体重和身高,然后单击calculate按钮,数据成功绘制到图表中,其相应的详细信息记录在页面底部,这正是我想要的,但问题是是用户输入的数据仅在第一次输入时成功显示,当我第二次输入数据时,后台计算正确完成并计算第二次输入的结果,但屏幕上没有任何变化,并且我只能看到第一个条目的结果,然后一旦我开始为第三个条目输入数据,我就会得到第一个的结果以及我之前输入的第二个条目显示在屏幕上,结果只在我开始时显示为下一个条目输入数据,而不是在单击calculate按钮后立即输入。 Here Is an example of what I want to achieve:这是我想要实现的一个例子: 在此处输入图片说明

And Here is a link of the repo if you want to test it in your machine: https://github.com/Marouane328/Bmi-tracker如果你想在你的机器上测试它,这里有一个 repo 的链接: https : //github.com/Marouane328/Bmi-tracker

In Graph, can you consider converting const data and const options to states and use useEffect to assign the props values to the states giving props has dependency for useEffect.在 Graph 中,您是否可以考虑将const dataconst options转换为状态,并使用 useEffect 将 props 值分配给状态,从而使 props 依赖于 useEffect。

try this it worked in your repo at codesandbox( https://codesandbox.io/s/peaceful-hofstadter-onso9 ):试试这个它在你的代码和盒子( https://codesandbox.io/s/peaceful-hofstadter-onso9 )的回购中工作:

const [data, setData] = React.useState({
    labels: props.dates,
    datasets: [
        {
            label: 'BMI',
            data: props.results,
            fill: 'origin',
            backgroundColor: '#16a5e1',
            pointBackgroundColor: '#16a5e1',
            pointBorderColor: 'blue',
            pointRadius: '4'
        },
    ],
});
const [options, setOptions] = React.useState({
    tension: 0.4,
    scales: {
        y: {
            ticks: {
                color: 'white'
            },
            beginAtZero: true
        },
        x: {
            ticks: {
                color: 'white'
            },
        }

    }
});

React.useEffect(
    ()=>{
        setData({
            labels: props.dates,
            datasets: [
                {
                    label: 'BMI',
                    data: props.results,
                    fill: 'origin',
                    backgroundColor: '#16a5e1',
                    pointBackgroundColor: '#16a5e1',
                    pointBorderColor: 'blue',
                    pointRadius: '4'
                },
            ],
        });
        setOptions({
            tension: 0.4,
            scales: {
                y: {
                    ticks: {
                        color: 'white'
                    },
                    beginAtZero: true
                },
                x: {
                    ticks: {
                        color: 'white'
                    },
                }
    
            }
        });
    },[props]
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM