Rilcon42
Rilcon42

Reputation: 9763

Passing the result of a component to render returns an undefined?

I am trying to write a wrapper component around an API call to render "loading" if the api hasnt updated. Im very new to react, but I can t seem to figure out why the state isnt being passed to the ApiResp component:

Here is the console.log of the state changes..... why is the final apiResp in console.log undefined?

enter image description here

App.js

class App extends React.Component {

  async componentDidMount() {
    let xx = await axios.get(apiUrl)
    console.log(`componentDidMount`, xx)
    this.setState({ loading: false, body: xx });
  }

  render() {
    console.log(`rendering ComponentLoading`, this.state)
    const DisplayComponent = ComponentLoading(ApiResp)
    return (
      <div className="App">
        <header className="App-header">
          <img src={face} /*className="App-logo"*/ alt="face-img" />
        </header>
        <br></br>
        <div>
          <DisplayComponent isLoading={AppState.loading} body={AppState.body} />
        </div>
      </div>
    );
  }
}
export default App;

ComponentLoading:

import React from 'react';

function ComponentLoading(Component) {
    return function WihLoadingComponent({ isLoading, ...props }) {
        if (!isLoading) return <Component {...props} />;
        return (
            <p style={{ textAlign: 'center', fontSize: '30px' }}>
                Loading
            </p>
        );
    };
}
export default ComponentLoading;

apiResp.js

import React from 'react';
const ApiResp = (data) => {
    console.log(`apiResp:`, data)
    if (!data || data.statusCode !== 200) {
        return <p>Err: {JSON.stringify(data)}</p>;
    }
    else
        return (
            <div>
                <h3>obj:</h3>
                {JSON.stringify(data)}
            </div>
        );
};
export default ApiResp;

Upvotes: 2

Views: 48

Answers (1)

Drew Reese
Drew Reese

Reputation: 203408

ComponentLoading is a Higher Order Component. const DisplayComponent = ComponentLoading(ApiResp) is decorating the ApiResp component:

const ApiResp = (data) => {
    console.log(`apiResp:`, data)
    if (!data || data.statusCode !== 200) {
        return <p>Err: {JSON.stringify(data)}</p>;
    }
    else
        return (
            <div>
                <h3>obj:</h3>
                {JSON.stringify(data)}
            </div>
        );
};

and returning a component you've called DisplayComponent.

As a component ApiResp is consuming a props object called data and only accesses a statusCode prop.

DisplayComponent is passed two props:

<DisplayComponent isLoading={AppState.loading} body={AppState.body} />

AppState isn't defined in the parent component but it seems this.state has the values you want passed to DisplayComponent.

Solution

Access and pass the correct object to props.

<DisplayComponent
  isLoading={this.state.loading}
  body={this.state.body}
/>

I suggest also moving the const DisplayComponent = ComponentLoading(ApiResp) declaration out of the render method, and also outside the App component.

const DisplayComponent = ComponentLoading(ApiResp);

class App extends React.Component {
  state = {
    loading: true,
    body: null,
  };

  async componentDidMount() {
    let xx = await axios.get(apiUrl)
    console.log(`componentDidMount`, xx)
    this.setState({ loading: false, body: xx });
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={face} /*className="App-logo"*/ alt="face-img" />
        </header>
        <br></br>
        <div>
          <DisplayComponent
            isLoading={this.state.loading}
            body={this.state.body}
          />
        </div>
      </div>
    );
  }
}

Upvotes: 1

Related Questions