reactjs - React 组件未使用 useEffects 重新渲染

标签 reactjs react-hooks render recharts

我目前正在创建一个前端应用程序,以显示 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/

相关文章:

javascript - react 保存使用重新渲染组件选择文本的可能性

使用等宽系列字体在 R 中渲染图不再显示字符

ruby-on-rails - 使用 { render json : } 时缺少属性

reactjs - react native : Text wrapping inside View container with fixed-width button

javascript - 如何使用 React Native 从 api 加载数据

reactjs - 如何摆脱这个 - 消息 : {'You are not subscribed to this API.' }. ?

javascript - 如何防止 CSS 渲染阻塞我的网站?

reactjs - React、Typescript 和一个 setState({ [name] : value }) error

reactjs - react : Trying to rewrite ComponentDidUpdate(prevProps) with react hook useEffect, 但它在应用程序启动时触发

reactjs - 使用React Hooks多次获取数据axios