Home > Software engineering >  One Component not re-rendering on state change while other is not
One Component not re-rendering on state change while other is not

Time:11-27

I'm trying to update the two child components on a button click. Since I'm passing functions to the child component I'm able to change the state. but the issue is state changes are not reflected on both child components. <AssetsTable/> is changing on state changes while <CryptoPieChart/> doesn't

      <Card>
        <CardBody>
          <div className="block w-full ">
            {this.state.Assets.length > 0 ? (
              <div className="grid ml-8 md:grid-cols-2 items-center">
                <div className="min-w-0">
                  <AssetsTable
                    Assets={this.state.Assets}
                    onDelete={this.onDeleteAsset}
                    onRefresh={this.onRefreshAsset}
                  />
                </div>
                <div className="mx-2 flex flex-col items-center min-w-0">
                  <p className="text-xl font-semibold text-gray-800 dark:text-gray-300">
                    Token Distribution
                  </p>
                  <CryptoPieChart
                    className="w-full"
                    Assets={this.state.Assets}
                  />
                </div>
              </div>
            ) : (
              ""
            )}
          </div>
        </CardBody>
      </Card>

<AssetTable/> code

import React from "react";

import {
  Table,
  TableCell,
  TableBody,
  TableRow,
  TableContainer,
  Button,
} from "@windmill/react-ui";
import { EditIcon, TrashIcon, RefreshIcon } from "../../icons";

class AssetsTable extends React.Component {
  constructor(props) {
    super(props);
  }

  async componentDidMount() {}

  render() {
    return (
      <>
        <TableContainer className="mb-8">
          <Table>
            <TableBody>
              {this.props.Assets.map((asset, i) => (
                <TableRow key={i}>
                  <TableCell className="">
                    <div className="flex items-center text-sm border-0">
                      <div className="relative rounded-full inline-block w-8 h-8 hidden mr-3 md:block">
                        <img
                          className="object-cover  rounded-circle circular-square "
                          src={asset.image}
                          alt="asset"
                          loading="lazy"
                        />
                        <div
                          className="absolute inset-0 rounded-full"
                          aria-hidden="true"
                        ></div>
                      </div>
                      <div>
                        <div className="font-semibold ">{asset.symbol}</div>
                        <p className="text-xs text-gray-600 dark:text-gray-400">
                          {asset.quantity} {asset.symbol}
                          {" * "}
                          {asset.current_price}
                        </p>
                      </div>
                    </div>
                  </TableCell>
                  <TableCell>
                    <span className="text-sm">$ {asset.usdValue}</span>
                  </TableCell>
                  <TableCell>
                    <div className="flex items-center space-x-4">
                      <Button
                        layout="link"
                        size="icon"
                        aria-label="Edit"
                        value={i}
                        onClick={this.props.onRefresh}
                      >
                        <RefreshIcon className="w-5 h-5" aria-hidden="true" />
                      </Button>

                      {i > 0 ? (
                        <Button
                          layout="link"
                          size="icon"
                          aria-label="Delete"
                          value={i}
                          onClick={this.props.onDelete}
                        >
                          <TrashIcon className="w-5 h-5" aria-hidden="true" />
                        </Button>
                      ) : null}
                    </div>
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </TableContainer>
      </>
    );
  }
}

export default AssetsTable;

<CryptoPieChart/> Code

import React from "react";
import Chart from "react-google-charts";
import { getScrtProvider } from "../../apis/scrt";

class CryptoPieChart extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      chartData: [],
    };

    this.RecreateDataArray();
  }

  async RecreateDataArray() {
    const wallet = await getScrtProvider();

    let dataArray = [];
    let total = this.props.Assets.length;
    let i;
    dataArray.push(["symbol", "value"]);
    for (i = 0; i < total;   i) {
      if (this.props.Assets[i].address !== wallet.address) {
        continue;
      }
      let totalValue =
        this.props.Assets[i].current_price * this.props.Assets[i].quantity;
      dataArray.push([this.props.Assets[i].symbol, totalValue]);
    }

    this.setState({ chartData: dataArray });
  }

  render() {
    return (
      <Chart
        width={"300px"}
        height={"300px"}
        chartType="PieChart"
        loader={<div>Loading Chart</div>}
        data={this.state.chartData}
        options={{
          legend: "none",
          pieSliceText: "label",
          colors: [
            "#024678",
            "#8accfd",
            "#7CB7E3",
            "#6EA3CA",
            "#608EB1",
            "#527A97",
            "#45657E",
            "#375165",
          ],
          backgroundColor: {
            fill: "#000000",
            fillOpacity: 0.0,
          },
        }}
        rootProps={{ "data-testid": "5" }}
      />
    );
  }
}

export default CryptoPieChart;

I don't see any difference. Please help

CodePudding user response:

You only call RecreateDataArray when the component mounts, not when props change.

That's why it doesn't update when your props change.

You could do that update with a componentWillUpdate lifecycle method, but it will be a lot easier to just refactor to a function component and use the useEffect hook instead:

import React from "react";
import Chart from "react-google-charts";
import { getScrtProvider } from "../../apis/scrt";

async function RecreateDataArray(assets) {
  const wallet = await getScrtProvider();

  let dataArray = [];
  let total = assets.length;
  let i;
  dataArray.push(["symbol", "value"]);
  for (i = 0; i < total;   i) {
    if (assets[i].address !== wallet.address) {
      continue;
    }
    let totalValue = assets[i].current_price * assets[i].quantity;
    dataArray.push([assets[i].symbol, totalValue]);
  }
  return dataArray;
}

function CryptoPieChart({ Assets }) {
  const [chartData, setChartData] = React.useState([]);
  React.useEffect(() => {
    RecreateDataArray(Assets).then(setChartData);
  }, [Assets]);

  return (
    <Chart
      width={"300px"}
      height={"300px"}
      chartType="PieChart"
      loader={<div>Loading Chart</div>}
      data={chartData}
      options={{
        legend: "none",
        pieSliceText: "label",
        colors: [
          "#024678",
          "#8accfd",
          "#7CB7E3",
          "#6EA3CA",
          "#608EB1",
          "#527A97",
          "#45657E",
          "#375165",
        ],
        backgroundColor: {
          fill: "#000000",
          fillOpacity: 0.0,
        },
      }}
      rootProps={{ "data-testid": "5" }}
    />
  );
}

export default CryptoPieChart;
  • Related