3

Hi I am fetching data from an api and I would like to take the data and render it to the dom but I am the error "Uncaught TypeError: Cannot read property 'map' of undefined at Topicselect.render"

Here is essentially what I am doing, although I have abstracted away anything that is not directly relevant to the question, such as actual topic names, imports, etc :

class Topics extends Component{
   constructor(props){
     super(props);
     this.state = {
       topics: []
     }
   }
    componentWillMount(){
        fetch('/api').then((res)=>r.json().then((data)=>{
               // push topics into this.state.topics somehow
        }) 
       console.log(this.state.topics) //returns ['topic1','topic2','topic3'];
    } 
   render(){
     const list = this.state.topics.map((topic)=>{
         return(<li>{topic}</li>);
     })
    return(
      <ul>
        {list}
      </ul>
     )
    }
}

Can anyone tell me how to fix this? I saw an answer on here that said to use componentDidMount instead of componentWillMount but that isn't working for me

2

2 Answers 2

2

You are missing a closing bracket ) after the fetch and it's indeed recommended to use componentDidMount() instead of componentWillMount() for fetching data from an API.

Also don't forget to use this.setState({ topics: data.howeverYourDataIsStructured }); after you receive the data from the API to ensure a rerender of the component.

class Topics extends Component{
  constructor(props){
    super(props);
    this.state = {
      topics: []
    }
  }

  componentDidMount() {
    fetch('/api').then((res)=>r.json().then((data)=>{
      this.setState({ topics: data.topics });
    }));
    console.log(this.state.topics) //returns [];
  }

  render() {
    console.log(this.state.topics) //returns [] the first render, returns ['topic1','topic2','topic3'] on the second render;
    return(
      <ul>
        {this.state.topics.map(topic => (
          <li>{topic}</li>
        ))}
      </ul>
    )
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Make sure you use setState() to update your state, otherwise render() won't be triggered to update the dom. Also make sure you don't just overwrite the current state but add your new topics to the old ones. (not relevant for this case, but still important to mention)

One way to do it would be:

componentDidMount() {
    var currentTopics = this.state.topics;
    fetch('/api').then((res) => r.json().then((data) => {
            currentTopics.push(data);
        }));
    this.setState({'topics': currentTopics});
}

But you can also call setState() inside the loop. setState() does not work synchronously so it will first wait if there are some other changes to be made before it will actually execute the changes and then trigger render.

componentDidMount() {
    fetch('/api').then((res) => r.json().then((data) => {
        this.setState((state) => ({ topics: [...state.topics, data]}));
    }));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.