4

I want to do something like this (doesn't work, obviously)
I could store the result in a state and have the component be rendered in the render() method, but the problem with that is I am making many calls and will have many res objects.I will end up with a lot of states to maintain, so I want to just return a component after axios calls instead of changing the many states every time. Is this possible?

 class InstanceViewer extends React.Component {                                   
    constructor(props) {                                                         
        super(props);                                                                                                            
        this.MyComponent = {}                                                                              
    }                                                                            

    componentWillMount() {                                                       
        getData()                                                      
    }
    getData(){
        axios.get('/myurl/', {})                              
            .then((res) => {                                                     
                this.MyComponent = <h1> res </h1>           
            });                                                 
    }
    // I just put this line there because I don't know the correct way to do this
    render(){return({this.MyComponent})} 
}                                                                          
Pear
  • 785
  • 2
  • 10
  • 19
  • `render(){return({this.MyComponent})}` i have never seen a render method like this - are you sure that this is correct? – messerbill Mar 02 '18 at 18:35
  • @messerbill I just put it there because I don't know how to do it. There were no errors but ofc nothing showed up. I am not sure if my idea is possible at all – Pear Mar 02 '18 at 18:39

3 Answers3

2

This is possible but not recommended. You skip the render lifecycle, so you have to force rerender after getting the data: Can you force a React component to rerender without calling setState?

But I recommend that you just keep res in the component state:

class InstanceViewer extends React.Component {                                   
constructor(props) {                                                         
    super(props);                                                                                                            
    this.state = {res: ""}                                                                              
}                                                                            

componentWillMount() {                                                       
    getData()                                                      
}
getData(){
    axios.get('/myurl/', {})                              
        .then((res) => {
            this.setState({res})      
        });                                                 
}
render(){return(<h1>{this.state.res}</h1>)} 
ku8ar
  • 217
  • 1
  • 2
  • 9
0

You can do this. You need to maintain a state. Whenever the data from api arrive, prepare the element and set the state with that element.

class InstanceViewer extends React.Component {                                   
    constructor(props) {                                                         
        super(props);                                                                                                            
        this.state = {MyComponent: null}                                                                              
    }                                                                            

    componentWillMount() {                                                       
        getData()                                                      
    }
    getData(){
        axios.get('/myurl/', {})                              
            .then((res) => {      
                let elem = <h1>{res}</h1>
                // Set the state with created element. It will rerender the component and this element will be displayed.
                this.setState({MyComponent: elem})             
            });                                                 
    }
    render(){
     return(
      <div>
       // Render the state. Initially it will be null but after api result, it will display the content.
       {this.state.MyComponent}
      </div> 
    )} 
}        
Prakash Sharma
  • 15,542
  • 6
  • 30
  • 37
  • This works! Thank you very much! I am wondering if this is good practice though? – Pear Mar 02 '18 at 19:09
  • @Pear I think the only problem with this approach is readability. By just looking at `render` function, you cannot tell the exact component tree. You will have to jump to `getData` function. I don't see any other problem with this approach. – Prakash Sharma Mar 02 '18 at 19:17
-1

The issue is your axios call is asynchronous and "this.MyComponent" is an empty object when it is returned. The state is updated with the response sometime later but you have executed the line of code with the reference to this.MyComponent while it is still an empty object. Hence, you don't see any errors AND you don't see any of the data you expect on the DOM element. The solution is a ternary operator that only renders this.MyComponent if the object contains the result you expect.