62

Let me preface this by saying I am a novice to ReactJS. I am trying to learn by making a simple site that populates data using React. I have a JSON file that contains link data that will be looped through with map.

I have tried setting it as the components state then passing it to the navbar links via a prop but I am getting "Uncaught TypeError: Cannot read property 'data' of null"

I tried to look around for solutions but could not find anything.

Note: When I try to hard code an object and map through it that way it returns map is undefined. However I am not sure that is directly related to the setState error.

/** @jsx React.DOM */

var conf = {
    companyName: "Slant Hosting"
  };

var NavbarLinks = React.createClass({
  render: function(){
    var navLinks = this.props.data.map(function(link){
      return(
        <li><a href={link.target}>{link.text}</a></li>
      );
    });
    return(
      <ul className="nav navbar-nav">
        {navLinks}
      </ul>
    )
  }
});

var NavbarBrand = React.createClass({
  render: function(){
    return(
      <a className="navbar-brand" href="#">{conf.companyName}</a>
    );
  }
});

var Navbar = React.createClass({
  getInitalState: function(){
    return{
      data : []
    };
  },
  loadNavbarJSON: function() {
    $.ajax({
      url: "app/js/configs/navbar.json",
      dataType: 'json',
      success: function(data) {
        this.setState({
          data: data
        });
        console.log(data);
        console.log(this.state.data);
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  componentDidMount: function(){
    this.loadNavbarJSON();
  },
  render: function(){
    return(
      <nav className="navbar navbar-default navbar-fixed-top" role="navigation">
        <div className="container-fluid">
          <div className="navbar-header">
            <NavbarBrand />
          </div>
          <NavbarLinks data={this.state.data} />
        </div>
      </nav>
    );
  }
});

var Header = React.createClass({
  render: function(){
    return(
      <Navbar />
    );
  }
});

React.renderComponent(
  <Header />,
  document.getElementById('render')
);
Matthew Wisniewski
  • 621
  • 1
  • 5
  • 3
  • 24
    you misspelled `getInitialState` (you're missing the 'i' right after the t in initial) – trekforever Oct 16 '14 at 17:31
  • 2
    Looks like @trekforever found your problem. As as aside, your `console.log(this.state.data)` probably won't print the correct results, as React will queue the `setState` call. If you want to print your state after a call to `setState` you have to supply a callback: `this.setState({something: 'blah'}, function() { console.log(this.state.something);});` – edoloughlin Oct 16 '14 at 22:02
  • @trekforever DERP, thanks! – Matthew Wisniewski Oct 17 '14 at 15:53
  • @edoloughlin Thanks for the additional info! – Matthew Wisniewski Oct 17 '14 at 15:53
  • 6
    I just had this problem, too. "Heh, a misspelling, how careless," I thought. Then I went and checked my code. I had also misspelled it. The exact same way. – chadoh Jun 24 '15 at 03:20

5 Answers5

74

Using ES6, the initial state must be created in your constructor for the React component class, like this:

constructor(props) {
    super(props)
    this.state ={
    // Set your state here
    }
}

See this documentation.

Alex
  • 7,405
  • 5
  • 46
  • 72
yussan
  • 2,144
  • 1
  • 18
  • 24
  • 1
    This one helps me. constructor(props: any) { super(props) this.state = { model: new RegistrationModel() } and NOT this.setState } Thanks – jayson.centeno Apr 13 '16 at 15:48
  • This worked for me. I was using this.setState(obj) in my constructor. Any reason why your approach worked over mine? – Shn_Android_Dev Aug 25 '19 at 18:38
16

This question has already been answered, but I came here by having a problem that can easily happen to anyone.

I was getting a console.log(this.state) to log null in one of my methods, just because I didn't write:

this.handleSelect = this.handleSelect.bind(this);

in my constructor.

So, if you're getting a null for this.state in one of your methods, check if you have bounded it to your component.

Cheers!

Edit (because of @tutiplain's question)

Why was I getting null for this.state?

Because I wrote console.log(this.state) in the method which wasn't bounded to my class (my handleSelect method). That caused this to point to some object higher in the object hierarchy (most probably the window object) which doesn't have a property named state. So, by binding my handleSelect method to this, I assured that whenever I write this in that method, it will point to the object in which the method is in.

I encourage you to read a really good explanation for this here.

Filip Savic
  • 1,828
  • 17
  • 23
  • This one actually helped me. Lots of outdated tutorials out there. But I don't understand why it works. If I am in the same class, isn't the state object shared between all methods of that class? Why do I have to manually bind "this" to the method? – tutiplain Dec 29 '17 at 19:56
  • I edited my comment with a brief explanation. Make sure to check out the link I left at the end. :) – Filip Savic Dec 30 '17 at 18:11
10

this.state.data is null in your example because setState() is async. Instead you can pass a callback to setState like so:

loadNavbarJSON: function() {
    $.ajax({
      url: "app/js/configs/navbar.json",
      dataType: 'json',
      success: function(data) {
        console.log(data);

        this.setState({data: data}, function(){
          console.log(this.state.data);
        }.bind(this));

      }.bind(this),
    });
  }

https://facebook.github.io/react/docs/component-api.html#setstate

Blair Anderson
  • 17,040
  • 7
  • 64
  • 96
9

More actual answer, for using ES7+ Classes:

export class Counter extends React.Component {
  state = { data : [] };
  ...
}

ES6 Classes (alredy was answered)

export class Component extends React.Component {
  constructor(props) {
    super(props);
    this.state = { data : [] };
  }
  ...
}
fl-web
  • 444
  • 5
  • 13
0

I had similar issue. In my case it was webpack-dev-server not re-compiling my stuff on the run properly.
I just restarted the dev server to get it working again.

Grigory Bogush
  • 93
  • 1
  • 11