coffeecoffeecoffee
coffeecoffeecoffee

Reputation: 13

TypeError: Cannot read property state of null

I am not able to get the data out of state and apply the map function on it. I keep getting the

TypeError: Cannot read property 'financials' of null.

axios gets the following object, {symbol: "AAPL", financials: Array(4)}, thats why i'm using this.state.financials.financials

class Fundamentals extends Component {
  state = {
    financials: null,
    headers: null
  };

  async componentDidMount() {
    console.log("componentDidMOunt");
    await axios
      .get("https://api.iextrading.com/1.0/stock/aapl/financials?period=annual")
      .then(res => {
        const financials = res.data;
        this.setState({ financials });
        console.log(financials);
      });

    console.log("componentDidMount finished setting the data for the table");
  }

  render() {
    // const headers = this.getHeaders1();
    return (
      <GridContainer>
        <GridItem xs={12} sm={12} md={12}>
          <Card>
            {this.state.financials.financials.map(items => items)} <-- i want to get the data out of state and later put it into a table. 
          </Card>
        </GridItem>
      </GridContainer>
    );
  }
}

Upvotes: 1

Views: 1288

Answers (3)

Revanth M
Revanth M

Reputation: 113

That error is because React tries to render before your API call completes, in which case this.state.financials still has its initial null value assigned to it.

Change the default value of financials as mentioned below

state = {
    financials: { financials: [] },
    headers: null
};

So the final code looks something like

class Fundamentals extends Component {
  state = {
    financials: { financials: [] },
    headers: null
  };

  async componentDidMount() {
    console.log("componentDidMOunt");
    await axios
      .get("https://api.iextrading.com/1.0/stock/aapl/financials?period=annual")
      .then(res => {
         const financials = res.data;
         this.setState({ financials });
         console.log(financials);
      });

      console.log("componentDidMount finished setting the data for the table");
   }

   render() {
     // const headers = this.getHeaders1();
     return (
       <GridContainer>
         <GridItem xs={12} sm={12} md={12}>
           <Card>
             {this.state.financials.financials.map(items => items)} <-- i want to get the data out of state and later put it into a table. 
           </Card>
         </GridItem>
       </GridContainer>
     );
  }
}

Upvotes: 1

sridhar
sridhar

Reputation: 622

Add a check before you actually render the data.

class Fundamentals extends Component {
  state = {
    financials: null,
    headers: null
  };

  async componentDidMount() {
    console.log("componentDidMOunt");
    await axios
      .get("https://api.iextrading.com/1.0/stock/aapl/financials?period=annual")
      .then(res => {
        const financials = res.data;
        this.setState({ financials });
        console.log(financials);
      });

    console.log("componentDidMount finished setting the data for the table");
  }

  render() {
    const { financials: { financials} } = this.state;

    if(!financials || (financials && !financials.length) {
      return (
        <LoaderComponent />
      )
    }

    return (
      <GridContainer>
        <GridItem xs={12} sm={12} md={12}>
          <Card>
            {financials.map(items => items)} <-- i want to get the data out of state and later put it into a table. 
          </Card>
        </GridItem>
      </GridContainer>
    );
  }
}

Upvotes: 1

Felix Kling
Felix Kling

Reputation: 817228

The first time the component renders, this.state.financials is null, because you are initializing it with null:

state = {
  financials: null,
  headers: null
};

And that's why you are getting that error. Here is a simple example that replicates the error:

var state = {
  financials: null,
};

state.financials.financials.map(() => {});

You need to check in your render method whether the value is set, and do nothing if it isn't:

render() {
  // const headers = this.getHeaders1();
  if (!this.state.financials) {
    return null; // or some message that the data is loading
  }

  return (
    <GridContainer>
      <GridItem xs={12} sm={12} md={12}>
        <Card>
          {this.state.financials.financials.map(items => items)} <-- i want to get the data out of state and later put it into a table. 
        </Card>
      </GridItem>
    </GridContainer>
  );
}

Alternatively you could initialize it with {financials: []} instead:

state = {
  financials: {financials: []},
  headers: null
};

Then your existing code inside render should "work" (see below).


But that alone likely won't make your component work. You also need to actually convert the entries in this.state.financials.financials to something that React can render. Here is an example that pulls out the date:

this.state.financials.financials.map(item => item.reportDate)

Adjust this to your needs.

Upvotes: 2

Related Questions