3

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

  • It depends on where exactly you log the state, and given that `this.setState` is async, you're probably doing it too early. Just add this to your JSX: `
    {JSON.stringify(this.state)}
    ` and you will see the state change just fine (also don't use `map` instead of `forEach`) see also here: https://stackoverflow.com/questions/41278385/setstate-doesnt-update-the-state-immediately
    –  Oct 02 '20 at 10:31
  • Can you show or explain where exactly you are console logging? – Chris Oct 02 '20 at 10:34
  • Hi Chris, thanks for your response, I was console logging just outside of the map inside the componentDidMount, and that one displayed the arrays fully built. Then I console logged inside the render (just above the return statement) and the arrays where empty – Diego Larraz Ramirez Oct 02 '20 at 10:42
  • I have included the line in my jsx and it still shows as an empty array – Diego Larraz Ramirez Oct 02 '20 at 10:44
  • What is displayed when you console log inside the render function? – Nicholas Oct 02 '20 at 10:44
  • Could you update the post with the way you included the line in the JSX? To check what's happening. – Nicholas Oct 02 '20 at 10:44
  • Also. is ever on of your if statement true? – Nicholas Oct 02 '20 at 10:45
  • Hi Nicholas, so the if statements do work, I know they do because when I console log in the componentDidMount I can see that the arrays were built and the state was set. – Diego Larraz Ramirez Oct 02 '20 at 10:51
  • I have updated the post with images and comments – Diego Larraz Ramirez Oct 02 '20 at 10:56
  • How about if we update the state once not for every if condition. Lets initialize variables before the mapping and update them in if condition and then after the map complete, update your state. Let's see if that sort your issue – Sameer Kumar Jain Oct 02 '20 at 11:01

2 Answers2

1

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];
critrange
  • 5,652
  • 2
  • 16
  • 47
1

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.

A.R.SEIF
  • 865
  • 1
  • 7
  • 25