96

I'm following the reactjs tutorial, and I keep running into an issue when
passing the value from the state of one component into another component.

The error Cannot read property 'map' of undefined' is thrown when the map function in the CommentList component is executed.

What would cause the prop to be undefined when passing from CommentBox into the CommentList?

// First component
var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.data.map(function (comment){
      return <div><h1>{comment.author}</h1></div>;
    });
    return <div className="commentList">{commentNodes}</div>;
  }
});
// Second component    
var CommentBox = React.createClass({
   getInitialState: function(){
     return {data: []};
   },
   getComments: function(){
      $.ajax({
        url: this.props.url,
        dataType: 'json',
        success: function(data){ this.setState({data: data}) }.bind(this),
        error: function(xhr, status, err){ console.error(url, status, err.toString()) }.bind(this)
      });
   },
   componentWillMount: function(){
      this.getComments()
   },
   render: function(){
      return <div className="commentBox">{<CommentList data={this.state.data.comments}/>}</div>;
   }
});

React.renderComponent( <CommentBox url="comments.json" />, document.getElementById('content'));
Community
  • 1
  • 1
Nael
  • 1,479
  • 1
  • 14
  • 20
  • Does this answer your question? [Line 0: Parsing error: Cannot read property 'map' of undefined](https://stackoverflow.com/questions/62079477/line-0-parsing-error-cannot-read-property-map-of-undefined) – Henke Mar 23 '22 at 14:00

11 Answers11

68

First of all, set more safe initial data:

getInitialState : function() {
    return {data: {comments:[]}};
},

And ensure your ajax data.

It should work if you follow above two instructions like Demo.

Updated: you can just wrap the .map block with conditional statement.

if (this.props.data) {
  var commentNodes = this.props.data.map(function (comment){
      return (
        <div>
          <h1>{comment.author}</h1>
        </div>
      );
  });
}
taggon
  • 1,896
  • 13
  • 11
  • 1
    This solution worked, but I'm curious. If I have a more complicated JSON structure, would I have to initialize the data object the same way? It seems like there should be a better way. Thanks – Nael Jul 12 '14 at 00:39
  • @Nael No, you don't need to. Just wrap the block like above. :) – taggon Jul 12 '14 at 00:48
  • 3
    The error occurs because `this.props.data` is null. `.map` expects to be called on an array. – timothyclifford Jul 15 '15 at 10:04
  • @timothyclifford thanks for the answer. I understand `this.props.data` is null which caused the map function to fail. But what I don't understand is that the tutorial code works without the if clause. Why `this.props.data` is not null in the tutorial? – Cheng Jul 15 '15 at 13:30
  • `this.props.data` is populated by the AJAX request. The AJAX is asynchronous so if the component is rendered before the data is populated, `this.props.data` will be null and you'll get the error. Does this make sense? – timothyclifford Jul 15 '15 at 13:47
  • Hi @timothyclifford, can I implement this by using props and geting the josn from server side? I am new in React, I think the data will not change after initiated so I want use props to implement this. But the problem just like you say the props.data is NULL – MichaelMao Mar 14 '16 at 06:12
  • Hi @MichaelMao would you like to post your question separately and show the code you have then we can help sort out any problems. – timothyclifford Mar 14 '16 at 09:59
  • Hi @timothyclifford In the final, I use state to implement it and it works good now. Thank you for your reply. – MichaelMao Mar 14 '16 at 10:31
  • This can also work, ```var commentNodes = this.props.data && this.props.data.map(function (comment){ return (

    {comment.author}

    ); });```
    – Gerard Banasig Jun 07 '17 at 06:51
14

I think you forgot to change

data={this.props.data}

to

data={this.state.data}

in the render function of CommentBox. I did the same mistake when I was following the tutorial. Thus the whole render function should look like

render: function() {
  return (
    <div className="commentBox">
      <h1>Comments</h1>
      <CommentList data={this.state.data} />
      <CommentForm />
    </div>
  );
}

instead of

render: function() {
  return (
    <div className="commentBox">
      <h1>Comments</h1>
      <CommentList data={this.props.data} />
      <CommentForm />
    </div>
  );
finrod
  • 521
  • 8
  • 21
11

You need to put the data before render

Should be like this:

var data = [
  {author: "Pete Hunt", text: "This is one comment"},
  {author: "Jordan Walke", text: "This is *another* comment"}
];

React.render(
  <CommentBox data={data}/>,
  document.getElementById('content')
);

Instead of this:

React.render(
  <CommentBox data={data}/>,
  document.getElementById('content')
);

var data = [
  {author: "Pete Hunt", text: "This is one comment"},
  {author: "Jordan Walke", text: "This is *another* comment"}
];
sfjac
  • 7,119
  • 5
  • 45
  • 69
Liliang Zhu
  • 111
  • 1
  • 5
7

The error "Cannot read property 'map' of undefined" will be encountered if there is an error in the "this.props.data" or there is no props.data array.

Better put condition to check the the array like

if(this.props.data){
this.props.data.map(........)
.....
}
avariant
  • 2,234
  • 5
  • 25
  • 33
Sayeed roshan
  • 179
  • 2
  • 5
6

I considered giving a comment under the answer by taggon to this very question, but well, i felt it owed more explanation for those interested in details.

Uncaught TypeError: Cannot read property 'value' of undefined is strictly a JavaScript error.
(Note that value can be anything, but for this question value is 'map')

It's critical to understand that point, just so you avoid endless debugging cycles.
This error is common especially if just starting out in JavaScript (and it's libraries/frameworks).
For React, this has a lot to do with understanding the component lifecycle methods.

// Follow this example to get the context
// Ignore any complexity, focus on how 'props' are passed down to children

import React, { useEffect } from 'react'

// Main component
const ShowList = () => {
  // Similar to componentDidMount and componentDidUpdate
  useEffect(() => {// dispatch call to fetch items, populate the redux-store})

  return <div><MyItems items={movies} /></div>
}

// other component
const MyItems = props =>
  <ul>
    {props.items.map((item, i) => <li key={i}>item</li>)}
  </ul>


/**
  The above code should work fine, except for one problem.
  When compiling <ShowList/>,
  React-DOM renders <MyItems> before useEffect (or componentDid...) is called.
  And since `items={movies}`, 'props.items' is 'undefined' at that point.
  Thus the error message 'Cannot read property map of undefined'
 */

As a way to tackle this problem, @taggon gave a solution (see first anwser or link).

Solution: Set an initial/default value.
In our example, we can avoid items being 'undefined' by declaring a default value of an empty array.

Why? This allows React-DOM to render an empty list initially.
And when the useEffect or componentDid... method is executed, the component is re-rendered with a populated list of items.

// Let's update our 'other' component
// destructure the `items` and initialize it as an array

const MyItems = ({items = []}) =>
  <ul>
    {items.map((item, i) => <li key={i}>item</li>)}
  </ul>
MwamiTovi
  • 2,425
  • 17
  • 25
4

Here is what my issue where:

{props.users.map((item,index)=>(
    <div className="items" key={index}>
        <div className="text-center">
            <p className="fs-12">{item}</p>
        </div>
    </div>
))}

And then i just fixed the issue with adding this code. It works just as if and else statement.

{ props.users ? props.users.map((item,index)=>(
        <div className="items" key={index}>
            <div className="text-center">
                <p className="fs-12">{item}</p>
            </div>
        </div>
)) : <p>Users is empty</p>}
Asbis
  • 432
  • 5
  • 16
2

The error occur mainly becuase the array isnt found. Just check if you have mapped to the correct array. Check the array name or declaration.

NeERAJ TK
  • 2,447
  • 1
  • 11
  • 25
0

in my case it happens when I try add types to Promise.all handler:

Promise.all([1,2]).then(([num1, num2]: [number, number])=> console.log('res', num1));

If remove : [number, number], the error is gone.

0

This worked for me. if i use props.worktyp.map it throws me an error of map is not defined.

//App.js
    const worktyp = [
          "Full-time",
          "casual",
          "part-time",
          "contract"
        ];
    
    function Main(props){
      return(
    <section>
      <p>This the main body</p>
      <ul style = {{textAlign:"left"}}>
        **{worktyp.map((work) => <li>{work}</li>)}**
      </ul>
    </section>
    
      );
        }
 function App() {
      return (
        <div className="App">
          <Header name="initial"/>
          **<Main work={worktyp}/>**
          <Foot year ={new Date().getFullYear()}/>
        </div>
      );
    }
//index.js
    ReactDOM.render(
     <App />,
      document.getElementById('root')
    );
Govardhan
  • 1
  • 1
0

react js when api call data app: [{programname: "string", status: "duplicate"}]

Vamshi
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 04 '22 at 01:05
0

In my case I solved this error by adding "?" condition.

Before:

<div className="hotelContainer__img">
              {photos.map((item, index) => (
                <img
                  src={item}
                  alt=""
                  key={index}
                  onClick={() => handleOpen(index)}
                />
              ))}
            </div>

After

<div className="hotelContainer__img">
              {photos?.map((item, index) => (
                <img
                  src={item}
                  alt=""
                  key={index}
                  onClick={() => handleOpen(index)}
                />
              ))}
            </div>