State outside of ComponentDidMount does not appear to update

Viewed 66

Hello when I console log the state of my component anywhere outside the componentDidMount method I get that my state is full of empty arrays when they should have been built. I am grabbing the data from a JSON file and inside the componentDidMount I can see that the state changes to arrays with data, however anywhere else such as in my render, the state is back to its initial state.

I imagine this problem has to do with the component's lifecycle so would love to understand what is going on.

Many thanks!

import React from 'react';
import * as metrics from './metrics.json';

class MetricsTable extends React.Component {
    state = {
        coverages: [],
        speeds: [],
        qualities: [],
        responsiveness: [],
        securities: []
    }

    componentDidMount() {
        metrics[0].map((metric) => {
            
            if (metric.level_1 === 'Coverage') {
                let joined = this.state.coverages.splice(0, 0, metric)
                this.setState({ coverages: [...joined] })
            }

            if (metric.level_1 === 'Speed') {
                let joined = this.state.speeds.splice(0, 0, metric)
                this.setState({ speeds: [...joined] })
            }

            if (metric.level_1 === 'Quality') {
                let joined = this.state.qualities.splice(0, 0, metric)
                this.setState({ qualities: [...joined] })
            }

            if (metric.level_1 === 'Responsiveness') {
                let joined = this.state.responsiveness.splice(0, 0, metric)
                this.setState({ responsiveness: [...joined] })
            }
            
            if (metric.level_1 === 'Security') {
                let joined = this.state.securities.splice(0, 0, metric)
                this.setState({ securities: [...joined] })
            }
        })
    }
    
    render() {
        // when I console log on this line I get empty arrays for my state
        return (
            <div>
                // this following line displays my state with empty arrays
                <pre>{JSON.stringify(this.state)}</pre>
                hello
            </div>
        );
        
    }
    
}

export default MetricsTable;

The fist picture shows state that has arrays with data, this one is console logged inside componentDidMount.

The second picture is the console log of this.state in my render function enter image description here

this is the console log in my render function

2 Answers

The problem is related to this kind of code:

let joined = this.state.coverages.splice(0, 0, metric)

Note that joined will be always an empty array. The splice method doesn't return a new result array.

You can update the code like this:

let joined = [...this.state.coverages, metric];

I rewrote the above code with a hook.

import React, { useState, useEffect } from "react";

let metrics = [
  [
    [
      {
        level_1: "Coverage",
        name: "Coverage_1"
      }
    ],
    [
      {
        level_1: "Speed",
        name: "Speed_1"
      }
    ]
  ]
];
const MetricsTable = () => {
  const [coverages, setcoverages] = useState([]);
  const [speeds, setspeeds] = useState([]);
  const [qualities, setqualities] = useState([]);
  const [responsiveness, setresponsiveness] = useState([]);
  const [securities, setsecurities] = useState([]);

  useEffect(() => {
    metrics[0].map((metric) => {
      console.log("metric = ", metric);
      if (metric[0].level_1 === "Coverage") {
        setcoverages(coverages.concat(metric));
      }

      if (metric[0].level_1 === "Speed") {
        setspeeds(speeds.concat(metric));
      }

      if (metric[0].level_1 === "Quality") {
        setqualities(qualities.concat(metric));
      }

      if (metric[0].level_1 === "Responsiveness") {
        setresponsiveness(responsiveness.concat(metric));
      }

      if (metric[0].level_1 === "Security") {
        setsecurities(securities.concat(metric));
      }
    });
  }, []);

  return (
    <div>
      coverages:{coverages.length}
      <br />
      speeds:{speeds.length}
      <br />
      qualities:{qualities.length}
      <br />
      responsiveness:{responsiveness.length}
      <br />
      securities :{securities.length}
    </div>
  );
};

export default MetricsTable;

i am consider metrics was sample


why remove joined? for example
var fruits = [];

var t= fruits.splice(0, 0, [{name:"Kiwi",id:"1"}]);
 console.log("t = ",t)

t is empty.and fruits not empty and contain data.

Related