Skip to content

Fetching JSON and rendering it with react

My fetch gives me the following JSON:

“{“name”:”John”,”age”:26,”city”:”London”}”

However when i try to render it on my page like this:

import React from 'react';
import './App.css';
import * as microsoftTeams from "@microsoft/teams-js";

class Tab extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      context: {}
    }
  }

  componentDidMount() {
    fetch("http://localhost/openims/json.php?function=getDocuments&input=")
      .then(res => res.json())
      .then(
        (result) => {
          this.setState({
            isLoaded: true,
            files: result.files
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      )
  }
  
  render() {  
    const { error, isLoaded, files } = this.state;
    if (error) {
      return <div>Error: {error.message}</div>;
    } else if (!isLoaded) {
      return <div>Loading...</div>;
    } else {
      return (     
        <ul>
          {files.map(file => (
            <li key={file.id}>
              {file.name} {file.age} {file.city}
            </li>
          ))}
        </ul>       
      );
    }
    
  }

}
export default Tab;

I get a TypeError: Cannot read property ‘map’ of undefined

How can i fix this?

Thanks in advance!

Answer

Given that the API response is {"name":"John","age":26,"city":"London"} then I suggest the following:

  1. Save the entire response result into state. Use a catch block to catch any errors and set any error state, and use a finally block to set the loading state (more DRY).

    componentDidMount() {
      fetch("http://localhost/openims/json.php?function=getDocuments&input=")
        .then(res => res.json())
        .then((result) => {
          this.setState({ ...result });
        })
        .catch((error) => {
          this.setState({ error });
        })
        .finally(() => {
          this.setState({ isLoaded: true })
        });
    }
    
  2. Render from state, no array, just the state fields.

    render() {  
      const { error, isLoaded, name, age, city } = this.state;
    
      if (error) {
        return <div>Error: {error.message}</div>;
      } else if (!isLoaded) {
        return <div>Loading...</div>;
      } else {
        return (     
          <ul>
            <li>
              {name} {age} {city}
            </li>
          </ul>       
        );
      }
    }