I’m working with reactjs and cannot seem to prevent this error when trying to display JSON data (either from file or server):
Uncaught TypeError: this.props.data.map is not a function
I’ve looked at:
React code throwing “TypeError: this.props.data.map is not a function”
React.js this.props.data.map() is not a function
Neither of these has helped me fix the problem. After my page loads, I can verify that this.data.props is not undefined (and does have a value equivalent to the JSON object — can call with window.foo
), so it seems like it isn’t loading in time when it is called by ConversationList. How do I make sure that the map
method is working on the JSON data and not an undefined
variable?
var converter = new Showdown.converter();
var Conversation = React.createClass({
render: function() {
var rawMarkup = converter.makeHtml(this.props.children.toString());
return (
<div className="conversation panel panel-default">
<div className="panel-heading">
<h3 className="panel-title">
{this.props.id}
{this.props.last_message_snippet}
{this.props.other_user_id}
</h3>
</div>
<div className="panel-body">
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
</div>
</div>
);
}
});
var ConversationList = React.createClass({
render: function() {
window.foo = this.props.data;
var conversationNodes = this.props.data.map(function(conversation, index) {
return (
<Conversation id={conversation.id} key={index}>
last_message_snippet={conversation.last_message_snippet}
other_user_id={conversation.other_user_id}
</Conversation>
);
});
return (
<div className="conversationList">
{conversationNodes}
</div>
);
}
});
var ConversationBox = React.createClass({
loadConversationsFromServer: function() {
return $.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadConversationsFromServer();
setInterval(this.loadConversationsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="conversationBox">
<h1>Conversations</h1>
<ConversationList data={this.state.data} />
</div>
);
}
});
$(document).on("page:change", function() {
var $content = $("#content");
if ($content.length > 0) {
React.render(
<ConversationBox url="/conversations.json" pollInterval={20000} />,
document.getElementById('content')
);
}
})
EDIT: adding sample conversations.json
Note — calling this.props.data.conversations
also returns an error:
var conversationNodes = this.props.data.conversations.map...
returns the following error:
Uncaught TypeError: Cannot read property ‘map’ of undefined
Here is conversations.json:
{"user_has_unread_messages":false,"unread_messages_count":0,"conversations":[{"id":18768,"last_message_snippet":"Lorem ipsum","other_user_id":10193}]}
Check out the information in this post. You will find the detailed instruction for the TypeError: map() is not a function in React. To avoid this error, you must make sure that you use the map() method on an array value. Let’s learn more about the cause and the most suitable approach to this problem.
Why do we have this error?
First, we have to know what causes you to get the error message: “TypeError: map() is not a function“. Look at the following example, it will throw this error:
export default function App() { const myChild = {name: 'Kai', age: 12}; return ( <div> {myChild.map(item => { return <h2>{item}</h2>; })} </div> ); };
Output:
The reason you receive this error message is that you are applying the map() method to a non-array object.
In JavaScript, the map() method creates an array by calling a specific function on each element contained in the parent array. So you cannot arbitrarily call the map() method without knowing the type of that object.
The simplest way to avoid this error is to use the map() method on an object that is an array, like the following example:
export default function App() { const friends = ['Celina','Nick','James','Tayor','Paul'] return ( <div> { friends.map(item => { return <h2>{item}</h2>; }) } </div> ); };
However, if you don’t know whether the value is really an array or not, you can use the Array.isArray() method to check.
export default function App() { const myChild = {name: 'Kai', age: 12}; return ( <div> { Array.isArray(friends) ? friends.map(item => { return <h2>{item}</h2>; }) : console.log('Object is not an array') } </div> ); };
In this example, the ternary operator is used for conditional rendering. In case the value is an array, the map() method will be called. Otherwise, you will get a message: “Object is not an array“.
In another case, you have an array-like object that you try to convert to an array before calling the map method using the Array.from() method.
export default function App(){ const friends = new Set(['Timmy', 'Carl', 'Jenny']); return ( <div> {Array.from(friends).map(element => { return ( <div key={item}> <h2>{item}</h2> </div> ); })} </div> ); };
We convert the value to an array before calling the map method. You can apply this approach to NodeList, which is returned when you call the getElementsByClassName method.
In case you work with an object, you will not be able to use the map() method to iterate through all the elements in the array because map() is only usable with array values.
At this point, you can use method Object.keys() to get the array of keys or method Object.values() to get the array of values of that object.
export default function App() { const myChild = { name: 'Kai', age: 12, }; return ( <div> {/*iterate over an object's array of keys*/} {Object.keys(myChild).map((key) => { return ( <div key={key}> <h2> {key} </h2> </div> ); })} <br /> {/*iterate over an object's array of values*/} {Object.values(myChild).map((value, idx) => { return ( <div key={idx}> <h2>{value}</h2> </div> ); })} </div> ); }
Summary
In conclusion, we have explained to you what causes the TypeError: map() is not a function in React. To avoid the error, you must call the map() method on an array object. Hopefully, the information in this article will help you.
Maybe you are interested:
- Property does not exist on type ‘never’ in React
- Module not found: Can’t resolve ‘babel-loader’
My name’s Christopher Gonzalez. I graduated from HUST two years ago, and my major is IT. So I’m here to assist you in learning programming languages. If you have any questions about Python, JavaScript, TypeScript, Node.js, React.js, let’s contact me. I will back you up.
Name of the university: HUST
Major: IT
Programming Languages: Python, JavaScript, TypeScript, Node.js, React.js
Я получаю данные из firebase через axios и хочу их отрендерить
Данные приходят в функцию рендер в виде массива объектов
Вот я вывел их в консоль:
После переборки выбивает ошибку TypeError: test.map is not a function
render() {
const test = this.props.users;
console.log('test', test);
return (
<div>
{
test.map(u => {
return <div key={u.id}>
<div>{u.fullName}</div>
</div>
})
}
</div>
)
}
Если те же данные вывести из компонента, все работает
render() {
const dataFromComponent = [
{id: 1, fullName: 'Max' },
{id: 2, fullName: 'Jordan' },
{id: 3, fullName: 'Gary' },
{id: 4, fullName: 'Oleg' }
]
return (
<div>
{
dataFromComponent.map(u => {
return <div key={u.id}>
<div>{u.fullName}</div>
</div>
})
}
</div>
)
}
При выводе:
if (!test.map ) {
console.log("props", {...this.props})
}
в консоль падает:
Loading
I’m looping through all anchor tag in an HTML with a class (.add-to-cart) to change text content to shop now, using map() but i am getting an error that says .map is not a function.
<!--HTML CODE -->
<div class="four columns">
<div class="card">
<a href="#" class="u-full-width button-primary button input add-to-cart" data-id="5">Add to Cart</a>
</div>
</div> <!--.card-->
<div class="four columns">
<div class="card">
<a href="#" class="u-full-width button-primary button input add-to-cart" data-id="5">Add to Cart</a>
</div>
</div> <!--.card-->
<div class="four columns">
<div class="card">
<a href="#" class="u-full-width button-primary button input add-to-cart" data-id="5">Add to Cart</a>
</div>
</div> <!--.card-->
//JAVASCRIPT CODE
const addCartBtns = document.querySelectorAll('.add-to-cart');
addCartBtns.map(function(cartBtn){
console.log(cartBtn.textContent="shop now");
});
I expect the output to change text content of anchor tags to «shop now».
asked Apr 7, 2019 at 16:39
1
document.querySelectorAll
returns a NodeList
which should be converted to real Array
before using map()
The Document method
querySelectorAll()
returns a static (not live)NodeList
representing a list of the document’s elements that match the specified group of selectors
You can use Spread Operator
const addCartBtns = [...document.querySelectorAll('.add-to-cart')]
Or you can can use Array.from
const addCartBtns = Array.from(document.querySelectorAll('.add-to-cart'))
Notice that you are using map()
. map()
is used when you want to create a new array bases on the values of existing array of same length. Here you are modifying the array. So you can use forEach
addCartBtns.forEach(function(cartBtn){
console.log(cartBtn.textContent="shop now");
});
Note:forEach
will work fine if NodeList
is not converted to array.
answered Apr 7, 2019 at 16:40
Maheer AliMaheer Ali
35.9k6 gold badges42 silver badges73 bronze badges
0
Here, you don’t actually need map
, forEach
will do, and NodeList has a forEach
. Therefore:
addCartBtns.forEach(function(cartBtn) {
console.log(cartBtn.textContent="shop now");
});
answered Apr 7, 2019 at 16:42
mbojkombojko
13.5k1 gold badge16 silver badges26 bronze badges