我目前正在创建一个前端应用程序,以显示 ML 的一些结果,并使用 React + Recharts。我的React版本是16.11.0,recharts版本是1.8.5。
每次更新数据时(每次迭代后),我都想更新图表。因此它首先显示 30 个点,这是预期的表现,但是当我添加 30 个新点,将用于显示数据的数组推至 60 个时,看起来我的组件没有重新渲染,并且只显示 30 个点。
所有逻辑似乎都很好:在我的主页侧,数据聚合正确完成,并且组件正确接收更新的数据。但我的图表仍然不会更新。
也许我用钩子(Hook)做错了事情,因为我还是一个初学者。感谢您的帮助。
主页代码,其中“simulateLocal”部分管理数据:
import React, { useEffect, useState } from "react";
import { TextField, Button } from "@material-ui/core/";
import Grid from "@material-ui/core/Grid";
import CardContent from "@material-ui/core/CardContent";
import Box from "@material-ui/core/Box";
import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/core/styles";
import Chart from "./Charts";
let results = []
let params = [];
const useStyles = makeStyles({
root: {
maxWidth: 400
},
title: {
fontSize: 20
}
});
async function initializeState(e, contract, accounts) {
await fetch("/init")
.then(res => res.json())
.then(data => {
console.log(data);
})
.catch(console.log);
}
async function simulateLocal(e, contract, accounts, setCount, count, setResult, result) {
//e.preventDefault();
console.log("Local stochastic gradient descent");
await contract.methods.resetState().send({ gas: 5000000, from: accounts[0] });
await fetch("/run_stage")
.then(res => res.json())
.then(data => {
params = data;
})
.catch(console.log);
console.log(contract);
await fetch("/get_results")
.then(res => res.json())
.then(data => {
if(results.length == 0 ){
results = { results : []}
}
data.results.forEach(result => {
result.name = (parseInt(result.name, 10) + results.results.length).toString();
})
results.results.push(...data.results);
setResult(results)
});
console.log(results);
setCount(count + 1);
}
async function simulateFederated(e, contract, accounts) {
e.preventDefault();
console.log("Federation happening.");
console.log(params);
for (var i = 0; i < 4; i++) {
await contract.methods
.store_params(params.weights[i])
.send({ from: accounts[i + 1], gas: 5000000 });
}
const aggres = await contract.methods
.run_agg()
.send({ gas: 5000000, from: accounts[0] });
console.log("runagg:" + aggres);
const weight_res = await contract.methods
.read_params()
.call({ gas: 500000000, from: accounts[0] });
console.log(weight_res);
for (var i = 0; i < 4; i++) {
await contract.methods
.store_params(params.biases[i])
.send({ from: accounts[i + 1], gas: 5000000 });
}
const aggres2 = await contract.methods
.run_agg()
.send({ gas: 500000000, from: accounts[0] });
console.log("runagg:" + aggres2);
const bias_res = await contract.methods
.read_params()
.call({ gas: 500000000, from: accounts[0] });
console.log(bias_res);
let postres = [];
await fetch("/post_params", {
method: "POST",
body: JSON.stringify({
weights: JSON.stringify(weight_res),
biases: JSON.stringify(bias_res)
})
})
.then(res => res.json())
.then(data => {
postres = data;
});
console.log(postres);
}
const ClientField = props => {
const [count, setCount] = useState(0);
const [result, setResult] = useState(results);
const classes = useStyles();
return (
<Box border={0} borderColor="grey.500">
<CardContent>
<Typography className={classes.header} variant="h6">
Simulation Panel
</Typography>
</CardContent>
<CardContent>
<Button
variant="contained"
size="small"
style={{
maxWidth: "100px",
maxHeight: "30px",
minWidth: "100px",
minHeight: "30px",
margin: "10px"
}}
onClick={e =>
simulateLocal(e, props.instance, props.accounts, setCount, count, setResult, result)
}
>
Run Local
</Button>
<Button
variant="contained"
size="small"
style={{
maxWidth: "100px",
maxHeight: "30px",
minWidth: "100px",
minHeight: "30px",
margin: "10px"
}}
onClick={e => simulateFederated(e, props.instance, props.accounts)}
>
Federate
</Button>
<Button
variant="contained"
size="small"
style={{
maxWidth: "100px",
maxHeight: "30px",
minWidth: "100px",
minHeight: "30px",
margin: "10px"
}}
onClick={e => initializeState(e, props.instance, props.accounts)}
>
Initialize
</Button>
</CardContent>
<CardContent
style={{
margin: "auto",
minHeight: "300px",
maxHeight: "300px",
maxWidth: "400px"
}}
>
<Chart data={result} count={count}></Chart>
</CardContent>
</Box>
);
};
export default ClientField;
以及使用 Recharts 库的图表组件。
import React, { useState, useEffect, useDeepCompareEffect } from "react";
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend
} from "recharts";
const Results = ({ data, count }) => {
const [result, setResult] = useState();
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
console.log("charts props:", data.results);
setResult(data.results)
console.log("results updated")
});
return (
<LineChart
width={500}
height={300}
data={result}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Line
type="monotone"
dataKey="uv"
stroke="#8884d8"
activeDot={{ r: 8 }}
/>
</LineChart>
);
};
export default Results;
最佳答案
在钩子(Hook)中,如果您使用相同的值更新状态,您的组件不会重新渲染。 如果你想重新渲染,那么你需要创建新的数组或对象。
如果 data.results 是数组,则执行
setResults([...data.results]);
如果 data.results 是对象则执行
setResults({...data.results});
关于reactjs - React 组件未使用 useEffects 重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61870263/