Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React + Typescript: How to define interface for an array that's populated from componentDidMount?

I am exploring React and Typescript and I stuck on a problem of how to define an interface for an array where are stored data from an API.

Here's what I have:

interface IState {
  loadingData: boolean;
  apiData: Array<string>;
}

class Contact extends Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
    this.state = {
      loadingData: true,
      apiData: []
    };
  }

  componentDidMount() {
    const apiUrl = 'http://jsonplaceholder.typicode.com/users';
    fetch(apiUrl)
      .then((response) => response.json())
      .then((data) => {
        console.log('This is your data', data);
        this.setState({ loadingData: false, apiData: data });
      })
      .catch(error => console.log('error: ', error));
  }
  ...

After running this code, though, I receive the following error:

Error: Objects are not valid as a React child (found: object with keys {id, name, username, email, address, phone, website, company}). If you meant to render a collection of children, use an array instead.
    in div (at Contact.tsx:39)
    in div (at Contact.tsx:33)
    in Contact (created by Context.Consumer)
    in Route (at Main.tsx:26)
    in div (at Main.tsx:23)
    in div (at Main.tsx:16)
    in Router (created by HashRouter)
    in HashRouter (at Main.tsx:15)
    in Main (at src/index.tsx:9)

What's the key to properly set up an interface for an array?

EDIT: Adding the render function:

render() {
    return (
      <div>
        <div>
          <h5>API Data</h5>
          {this.state.loadingData ? (
              'Loding data...'
            ) : (
              this.state.apiData
            )
          }
        </div>
      </div>
    );
  }
like image 389
user984621 Avatar asked Oct 15 '25 05:10

user984621


1 Answers

You can't render an array in react.

{this.state.loadingData ? (
   'Loding data...'
  ) : (
    this.state.apiData 
     && this.state.apiData.map(item => <p key={item.id}>{item.name}</p>
  )
}

this.state.apiData && this.state.apiData.map will check if apiData exists (not falsy, this won't protect you from it being a wrong type) and then run call the map.

And you need to update your interface

interface IState {
  loadingData: boolean;
  apiData: ApiData[];
}

interface ApiData {
  id: string
  name: string
  ...
}
like image 167
k.s. Avatar answered Oct 17 '25 21:10

k.s.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!