0

I have a component, which has to download a JSON file and then iterate over it and display each element from the JSON on the screen.

I'm kinda new with React, used to be ng dev. In Angular, I used to do it with lifecycle hooks, e.g. ngOnInit/ngAfterViewInit (get some JSON file and then lunch the iteration func). How can I achieve it in React? Is it possible to reach it with lifecycle hooks, like ComponentWillMount or ComponentDidMount.

My code (it's surely wrong):

export default class ExampleClass extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      data: [],
    }
  }

  componentWillMount(){
    getData();
  }

  render() {   
    return (
      <ul>
        {this.state.data.map((v, i) => <li key={i}>{v}</li>)}
      </ul>
    )

  };
}

const getData = () => {
  axios.get(//someURL//)

    .then(function (response) {
      this.setState({data: response.data});
    })
    .catch(function (error) {
      console.log(error);
    })
};

How to force React to get the JSON before rendering the component?

Thank you so much.

H. Doe
  • 545
  • 2
  • 5
  • 12
  • Yes, use `ComponentWillMount` is one way, just make sure you bind `this` correctly so that `this.setState` refers to the component! You could also just make the get request in the constructor function. – therobinkim May 27 '17 at 22:42
  • Possible duplicate of [How to show a loading indicator in React Redux app while fetching the data?](https://stackoverflow.com/questions/35456935/how-to-show-a-loading-indicator-in-react-redux-app-while-fetching-the-data) – Andy Ray May 27 '17 at 22:45

2 Answers2

2

You can do a simple if statement in your render function.

render () {
  if (Boolean(this.state.data.length)) {
    return <ul>{this.state.data.map((v, i) => <li key={i}>{v}</li>)}</ul>
  }
  return null
}

You can also use a higher order component to do the same thing.

const renderIfData = WrappedComponent => class RenderIfData extends Component {
  state = {
    data: []
  }
  componentWillMount() {
    fetchData()
  }
  render() {
     if (Boolean(this.state.data.length)) {
       return <WrappedComponent {...this.state} />
     }
    return null
  }
}

Then you can wrap the presentational layer with the HOC.

renderIfData(ExampleClass)

Not sure what version of React you are using but you may need to use <noscript> instead of null.

This is essentially preventing your component from rendering until it has all the data.

Adam Recvlohe
  • 334
  • 1
  • 11
2

Making an AJAX request in ComponentWillMount works. https://facebook.github.io/react/docs/react-component.html#componentwillmount

You could also just work that logic into your constructor depending on your exact needs. https://facebook.github.io/react/docs/react-component.html#constructor

export default class ExampleClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      data: [],
    }
    axios.get(/*someURL*/)
      .then(function (response) {
        this.setState({data: response.data});
      })
      .catch(function (error) {
        console.log(error);
      })
  }
}
therobinkim
  • 2,500
  • 14
  • 20
  • This is weird, but when Im using componentWillMount, im not able to assign the returned obj to any variable, because no variable exists when it's being done... – H. Doe May 27 '17 at 23:32
  • @H.Doe I don't understand what you're saying, please edit your question with an example of what it means for "no variable exists." – therobinkim May 28 '17 at 02:43