You probably need to pass in key={posts[p].data.id} and same for the rest of your props. What does your posts look like?
[Reactjs + Laravel] .map is not a function
Hello all friends, as I wrote in some of my previous posts, I am trying to build a simple e-learning platform in Reactjs and I'm doing my Restful API with Laravel. On the Laravel side, I had several CORS administration issues which I have now thankfully resolved (thanks especially for your help). The Reactjs side, on the other hand, was very good when, during the construction of the Home, I received this error in the browser: "posts.map is not a function" (I also link a screenshot of the error that appears in the console: link ). I think this error is due to the fact that in my API, the posts are not inside an Array, so I modified my code which was initially this:
<div>
{
posts.map(p =>
<
Publication
title={p.title}
author={p.author}
date={p.date}
content={p.content}
key={p.id}
/>)
}
</div>
this way:
Object.keys(posts).map(
p =>
<
Publication key={posts.data.id}
title={posts.data.title}
author={posts.data.author}
date={posts.data.date}
content={posts.data.content}
/>
)
By making this change, I thought I had solved all the problems, but it really is not because the Home page is not "filled" with data from my database and in my console, I have this warning: "each child in a list should have a unique "key" prop. I just can't figure out where I'm going wrong since if you look at my code I gave the value "key" to my "Publication" component and I also don't understand why the data of the database are not "compiled" on the page. Could you help me to solve these problems?
Thanks in advance to anyone who helps me (now I publish practically one post a day in this community, I know you really have a lot of patience with me) .
Greetings
Alessandro
@apex1 Hi apex, thank you for your reply. In my db, my posts (just like any other table), look like a json object.
I tried to apply the change you suggested but now, in my console, this warning appears: "Uncaught TypeError: Cannot read property 'title' of undefined". Here it is a link to an image of the complete error I have in my console: link.
How to solve it?
Once again thanks for the help you are giving me.
const posts = {
myid: {
id: 'myid',
title: 'random title',
author: 'random author',
...
},
myid2: {
id: 'myid2',
title: 'random title2',
author: 'random author2',
...
}
}
Looks like something like this? You mentioned it wasn't stored as an array. What's posts.data? Are you using axios to on the frontend?
If the posts look like above, then
Object.keys(post).map(post => (
<Publication
key={posts[post].id}
title={posts[post].title}
...
/>
));
@apex1 Thank you apex, this is the result that the Postman App give me when I do a petition to the posts using GET method:
{
"data": [
{
"id": 1,
"created_at": "2020-05-02T15:44:30.000000Z",
"updated_at": "2020-05-02T15:44:30.000000Z",
"author": "Amministratore",
"title": "Primo post di prova",
"date": "Today",
"content": "Questo è un post di prova ed è il primo post di questa community."
},
{
"id": 2,
"created_at": "2020-05-02T15:45:17.000000Z",
"updated_at": "2020-05-02T15:45:17.000000Z",
"author": "Amministratore",
"title": "Primo post di prova",
"date": "Today",
"content": "Questo è un post di prova ed è il secondo post di questa community."
},
{
"id": 3,
"created_at": "2020-05-02T15:45:25.000000Z",
"updated_at": "2020-05-02T15:45:25.000000Z",
"author": "Amministratore",
"title": "Primo post di prova",
"date": "Today",
"content": "Questo è un post di prova ed è il terzo post di questa community."
},
{
"id": 4,
"created_at": "2020-05-02T15:45:33.000000Z",
"updated_at": "2020-05-02T15:45:33.000000Z",
"author": "Amministratore",
"title": "Primo post di prova",
"date": "Today",
"content": "Questo è un post di prova ed è il quarto post di questa community."
},
{
"id": 5,
"created_at": "2020-05-03T19:42:40.000000Z",
"updated_at": "2020-05-03T19:42:40.000000Z",
"author": "Amministratore",
"title": "pprofondimenti della lezione di oggi di lingua francese 4",
"date": "03/05/2020 alle 21:26",
"content": "Questi sono tutti post d'esempio"
}
],
"status": 200
}
Oh so you just need to do, assuming it's stored in a posts variable
<div>
{posts.data.map(post => (
<Publication
key={post.id}
title={post.title}
/>)
)}
</div>
@apex1 really thank you very much apex
No prob, hope it fixed your issue. If you need any help related to React or JS send me a message anytime.
Yes, my problem has been solved. Thanks again... really.
Thanks above all for the availability you are demostrating to me
@apex1 Hi again apex sorry to bother you again, but during the development of the individual course pages (as I said I'm trying to build a platform quite simple e-learning), the usual problem arose again. This is the code I have tried:
import React, {useEffect} from "react";
import store from "../../redux/store";
import {getCourse} from "../../redux/actionCreators";
import { connect } from "react-redux";
import Banner from "../Organisms/Banner";
const Course = ({ course }) => {
useEffect(() => {
store.dispatch(getCourse(1))
}, [])
return (
<>
{
course &&
<>
{
<div>
{course.data.map(c => (
<Banner
color="first-color"
key={c.id}
title={c.name}
picture={c.picture}
subtitle={c.subtitle}
image={{
src:c.picture,
alt:c.name
}}
home
/>)
)}
</div>
}
</>
}
</>
)
}
const mapStateToProps = state => ({
course: state.courseReducer.course
})
export default connect(mapStateToProps, {})(Course)
But as usual in my console, this error appears: "TypeError: course.data.map is not a function".
This, instead, is the response I receve by the Postman app when I do a petition to courses using the GET method:
{
"data": [
{
"id": 1,
"created_at": null,
"updated_at": null,
"name": "Corso di lingua spagnola 1",
"subtitle": "Corso di lingua spagnola di primo livello",
"picture": "https://i.ibb.co/GsSknPk/spanish.jpg",
"information": "Corso base di lingua spagnola",
"you_learn": "Imparerai le basi della lingua spagnola",
"requirements": "Nessuno",
"level": "Base",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 2,
"created_at": "2020-05-02T14:16:44.000000Z",
"updated_at": "2020-05-02T14:16:44.000000Z",
"name": "Corso - Lingua italiana 1",
"subtitle": "Corso base di lingua italiana",
"picture": "https://i.ibb.co/wy5Brrj/italian-758576.png",
"information": "Lingua italiana primo livello",
"you_learn": "Imparerai le basi della lingua italiana",
"requirements": "Nessuno",
"level": "Base",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Tomorrow",
"slug": "Nessuna"
},
{
"id": 3,
"created_at": "2020-05-02T14:30:38.000000Z",
"updated_at": "2020-05-02T14:37:24.000000Z",
"name": "Corso - Lingua spagnola 2",
"subtitle": "Corso base di lingua spagnola",
"picture": "https://i.ibb.co/dGH0Xfm/spanish-758590-1920.png",
"information": "Lingua spagnola secondo livello",
"you_learn": "Imparerai le basi della lingua spagnola",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 4,
"created_at": "2020-05-02T14:30:53.000000Z",
"updated_at": "2020-05-02T14:37:32.000000Z",
"name": "Corso - Lingua spagnola 3",
"subtitle": "Corso base di lingua spagnola",
"picture": "https://i.ibb.co/dGH0Xfm/spanish-758590-1920.png",
"information": "Lingua spagnola terzo livello",
"you_learn": "Imparerai le basi della lingua spagnola",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 5,
"created_at": "2020-05-02T14:31:28.000000Z",
"updated_at": "2020-05-02T14:37:41.000000Z",
"name": "Corso - Lingua spagnola 4",
"subtitle": "Corso base di lingua spagnola",
"picture": "https://i.ibb.co/dGH0Xfm/spanish-758590-1920.png",
"information": "Lingua spagnola quarto livello",
"you_learn": "Imparerai le basi della lingua spagnola",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 6,
"created_at": "2020-05-02T14:34:42.000000Z",
"updated_at": "2020-05-02T14:37:46.000000Z",
"name": "Corso - Lingua spagnola 5",
"subtitle": "Corso base di lingua spagnola",
"picture": "https://i.ibb.co/dGH0Xfm/spanish-758590-1920.png",
"information": "Lingua spagnola quinto livello",
"you_learn": "Imparerai le basi della lingua spagnola",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 7,
"created_at": "2020-05-02T14:35:13.000000Z",
"updated_at": "2020-05-02T14:37:55.000000Z",
"name": "Corso - Lingua spagnola 6",
"subtitle": "Corso base di lingua spagnola",
"picture": "https://i.ibb.co/dGH0Xfm/spanish-758590-1920.png",
"information": "Lingua spagnola sesto livello",
"you_learn": "Imparerai le basi della lingua spagnola",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 8,
"created_at": "2020-05-02T14:35:27.000000Z",
"updated_at": "2020-05-02T14:37:59.000000Z",
"name": "Corso - Lingua spagnola 7",
"subtitle": "Corso base di lingua spagnola",
"picture": "https://i.ibb.co/dGH0Xfm/spanish-758590-1920.png",
"information": "Lingua spagnola settimo livello",
"you_learn": "Imparerai le basi della lingua spagnola",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 9,
"created_at": "2020-05-05T17:54:38.000000Z",
"updated_at": "2020-05-05T17:54:38.000000Z",
"name": "Corso - Lingua tedesca 7",
"subtitle": "Corso avanzato di lingua tedesca",
"picture": "https://i.ibb.co/nrxVwbK/Tedesco-3.png",
"information": "Lingua tedesca settimo livello",
"you_learn": "Imparerai le basi della lingua tedesca",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 10,
"created_at": "2020-05-05T17:55:08.000000Z",
"updated_at": "2020-05-05T17:55:08.000000Z",
"name": "Corso - Lingua tedesca 6",
"subtitle": "Corso avanzato di lingua tedesca",
"picture": "https://i.ibb.co/nrxVwbK/Tedesco-3.png",
"information": "Lingua tedesca settimo livello",
"you_learn": "Imparerai le basi della lingua tedesca",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 11,
"created_at": "2020-05-05T17:55:19.000000Z",
"updated_at": "2020-05-05T17:55:19.000000Z",
"name": "Corso - Lingua tedesca 5",
"subtitle": "Corso avanzato di lingua tedesca",
"picture": "https://i.ibb.co/nrxVwbK/Tedesco-3.png",
"information": "Lingua tedesca settimo livello",
"you_learn": "Imparerai le basi della lingua tedesca",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 12,
"created_at": "2020-05-05T17:55:26.000000Z",
"updated_at": "2020-05-05T17:55:26.000000Z",
"name": "Corso - Lingua tedesca 4",
"subtitle": "Corso avanzato di lingua tedesca",
"picture": "https://i.ibb.co/nrxVwbK/Tedesco-3.png",
"information": "Lingua tedesca settimo livello",
"you_learn": "Imparerai le basi della lingua tedesca",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 13,
"created_at": "2020-05-05T17:55:31.000000Z",
"updated_at": "2020-05-05T17:55:31.000000Z",
"name": "Corso - Lingua tedesca 3",
"subtitle": "Corso avanzato di lingua tedesca",
"picture": "https://i.ibb.co/nrxVwbK/Tedesco-3.png",
"information": "Lingua tedesca settimo livello",
"you_learn": "Imparerai le basi della lingua tedesca",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 14,
"created_at": "2020-05-05T17:55:37.000000Z",
"updated_at": "2020-05-05T17:55:37.000000Z",
"name": "Corso - Lingua tedesca 2",
"subtitle": "Corso avanzato di lingua tedesca",
"picture": "https://i.ibb.co/nrxVwbK/Tedesco-3.png",
"information": "Lingua tedesca settimo livello",
"you_learn": "Imparerai le basi della lingua tedesca",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
{
"id": 15,
"created_at": "2020-05-05T17:55:44.000000Z",
"updated_at": "2020-05-05T17:55:44.000000Z",
"name": "Corso - Lingua tedesca 1",
"subtitle": "Corso avanzato di lingua tedesca",
"picture": "https://i.ibb.co/nrxVwbK/Tedesco-3.png",
"information": "Lingua tedesca settimo livello",
"you_learn": "Imparerai le basi della lingua tedesca",
"requirements": "Nessuno",
"level": "Avanzato",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
}
],
"status": 200
}
and the route I use to reach every single course, is: "http://127.0.0.1:8000/api/courses/{id}"
Where did I go wrong this time?
Thanks a lot again
What do you get when you console.log(course) ?
You should only be getting a single entity of course, you would need to just do
<div>
{course && (
<Banner
key={course.id}
title={course.name}
...
/>
)}
</div>
You shouldn't be getting an array since it's just a single course, therefore the error,
course.data.map is not a function
Also, if I remember correctly, you generally don't need to or want to bring in the store either. Pass in your getCourse to your dispatchToProps down in the connect function.
export default connect(mapStateToProps, { getCourse })(Course)
It'll automatically be wrapped in a dispatch and you'll be able to use it as a prop. If you didn't know, Redux also has hooks now, making redux a lot easier to use. No need to connect, or any of that. They also have a new package @reduxjs/toolkit that helps with a lot of the boilerplate.
Hope this helps.
@apex1 Sorry Apex, I know that I disturb you constantly (you'll be hating me right now, I know it :) ), I always get the usual "course.lesson.map is not a function" problem but this time, I think I did everything correctly (if not, then, I didn't really understand the basic concept). Take a look at my code:
<main className="ed-grid lg-grid-10">
<div className="lg-cols-7">
<div className="course-features">
</div>
<h2>Sommario del corso</h2>
<div>
{course.lesson.map(course => (
<div key={course.id}>
<h3>{course.name}</h3>
</div>
))}
</div>
</div>
</main>
What I'm trying to raech is to "imprint" in my single course page, the summary of the various lessons of which the course itself is composed, therefore, I modified my API so as to nest the related informations and by doing this I obtained this result (always from my Postaman app):
{
"course": {
"id": 1,
"created_at": null,
"updated_at": null,
"name": "Corso di lingua spagnola 1",
"subtitle": "Corso di lingua spagnola di primo livello",
"picture": "https://i.ibb.co/GsSknPk/spanish.jpg",
"information": "Corso base di lingua spagnola",
"you_learn": "Imparerai le basi della lingua spagnola",
"requirements": "Nessuno",
"level": "Base",
"course_type": "Corso",
"visible": 1,
"coming": 0,
"coming_date": "Today",
"slug": "Nessuna"
},
"lesson": {
"id": 1,
"created_at": "2020-05-02T15:48:00.000000Z",
"updated_at": "2020-05-06T08:06:13.000000Z",
"name": "Introduzione allo spagnolo",
"video": "https://vimeo.com/411959274"
},
"teacher": {
"id": 1,
"created_at": "2020-05-02T15:54:22.000000Z",
"updated_at": "2020-05-02T15:54:22.000000Z",
"name": "Amari Orietta",
"picture": "https://i.ibb.co/nRnXMfx/amari.jpg",
"country": "Italy",
"city": "Palermo"
},
"status": 200
}
What I really don't understand is: to reach the single lesson, according to my API, shouldn't I just be doing "course.lesson.map"?
In fact, if I go to the "Redux" tab of my browser and navigate in it to the "Action" tab, I find the following structure (I put here a link to an image of the structure): Redux/Action Tab Structure.
Instead, nothing is "imprinted" on the page and I get the error I told you about.
I thought I finally understood this concept (thanks above all to your help) but evidently it is not so, where am I wrong?
Thanks once again for your help and above all for your patience.
Course isn't an array which is why you can use .map() on it. It's an object with nested objects. If you need to access properties in an object you can use dot notation or the [bracket] syntax.
In order to access the lesson and it's name inside a course, you would need to do
{course.lesson.name}
Please or to participate in this conversation.