jen007
jen007

Reputation: 1589

Is it possible to access state variable outside of react render function?

Is it possible to access state variables outside of render(), but inside react custom component method?

  componentDidMount() {
    fetch(
      "some url here"
    )
      .then(res => res.json())
      .then(json => {
        const days = this.getRainyDays(json)

        this.setState({
          data: json,
          rainyDays: days
        });
      });
  }

 getRainyDays = (data) => {
    console.log('data inside getRainyDays', this.state.data) // this.state.data is undefined here
    console.log('data inside getRainyDays2', data) // data returns json fine
  }

  render() {
   console.log(this.state.data) // this.state.data is fine too.
    return (
      <div className="App">
        <header className="App-header">
          Calendar showing {this.state.rainyDays} rainy days
        </header>
        <Year weatherData={this.state.data} />
        <Weather />
      </div>
    );
  }

Upvotes: 1

Views: 4819

Answers (1)

goto
goto

Reputation: 4425

Yes, it is possible to access state inside of a component outside of the render method.

According to the React documentation:

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall.

Since your initial state most likely doesn't have the data property set to some value, it comes back as undefined.

You're trying to access this.state.data inside of getRainyDays before you even call this.setState inside of componentDidMount:

componentDidMount() {
  fetch(...)
    .then(json => {
      const days = this.getRainyDays(json)
      this.setState(...)
    })
}

getRainyDays = (data) => {
  console.log('data inside getRainyDays', this.state.data)
}

But even if you called this.getRainyDays after this.setState, you cannot rely on this.setState updating your state immediately.

Again, from React documentation:

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.

If you would like to double check, however, that your state updates correctly, you can pass a callback to setState that will get called after setState updates component's state, like so:

componentDidMount() {
  fetch(..)
    .then(res => res.json())
    .then(json => {
      const days = this.getRainyDays(json)

      this.setState({
        data: json,
        rainyDays: days
      }, () => {
        console.log('data in state', this.state.data)
      });
    });
}

One thing that I'd recommend, is to check, inside your render function, whether state has the right data in it before you return some JSX. You might run into issues where some components expects an array of items and it renders it immediately, but you're passing undefined to it and it crashes...

render() {
  // exit early and return `null` so that nothing gets rendered
  // if your API call hasn't finished
  if (!this.state.data || !this.state.rainyDays) {
    return null
  }
  return (
    <div className="App">
      <header className="App-header">
        Calendar showing {this.state.rainyDays} rainy days
      </header>
      <Year weatherData={this.state.data} />
      <Weather />
    </div>
  );
}

Upvotes: 1

Related Questions