skip to Main Content

I have a React component which is pulling an API from an express url, /profile/:id. I am receiving the data correctly via the API. Additionally, the logging in the browser supports that the state of data and urls is set correctly.

However, the render() function is throwing an error because of this line this.state.urls.map((url) =>. I’m assuming the error is happening because the rendering is occurring before the state is set (even though I’m using componentDidMount).

What changes do I need to make to allow the render function’s item line to iterate over urls array?

The error I’m seeing is Uncaught TypeError: Cannot read properties of null (reading 'urls')

import React from 'react';
import ReactDOM from 'react-dom';
import {  Tabs } from 'antd';

export class TestResults extends React.Component {
    constructor(props){
        super (props);
        
    }
    getProfileData (){
        const fetchAndSetData = async () => {
          const response = await fetch('/profile/' + this.props.profileId);
          this.setState({data: await response.json()})
          console.log(`States ${JSON.stringify(this.state)}`)
          this.setState({urls: this.getUrls()});
        }
        fetchAndSetData()
    }
    componentDidMount(){
        this.getProfileData();
    }
    getUrls(){
        const urls = [];
        console.log("Calling URLs " + JSON.stringify(this.state))
        for (var x = 0; x < this.state.data.length; x++){
            urls.push(this.state.data[x].url)
        }
        console.log("URLs are " + urls)
        return urls
    }
    render (){
        
        return(
            <div>
                <Tabs
                    defaultActiveKey="1"
                    type="card"
                    size="large"
                    items={this.state.urls.map((url) => {
                      return {
                          label: `${url}`,
                          key: 1,
                          children: `Somne content for ${url}`,
                      };
                  })}
                />
            </div>
        );
    }
} 

2

Answers


  1. Optional Chaining

    You guessed it right. The problem is urls array is when map() method get called.

    so you cloud check whether it is undefined by using ? Optional Chaining

    this?.state?.urls?.map(...)
    

    React Functional Component

    With functional component managing the code will be much easier.so I thought why not add some codes.

    const TestResults () => {
    
        const [data,setData] = useState({})
        const [urls,setUrls] = useState([])
        const [profileId,setProfileId] = useState([])
    
        async getProfileData (){
            const fetchAndSetData = async () => {
              const response = await fetch('/profile/' + profiled);
              const fetched = await response.json()
              setData(fetched)
              setUrls(fetched.map(item=> item.url));
            }
        }
     
       useEffect(()=>{
         getProfileData ()
       },[])
      
       return(
            <div>
                <Tabs
                    defaultActiveKey="1"
                    type="card"
                    size="large"
                    items={urls?.map(url => {label: `${url}`,key: 1,children: `Somne content for ${url}`,
                  })}
                 />
             </div>
       )
    
    }
    
    Login or Signup to reply.
  2. Another option is to set urls to an empty list initially. In the constructor you can do:

    this.state = {urls: []}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search