How do I fix this to show a variable number of menuitems? - javascript

I have this basic example, and I can see each menuitem by subscript, but the .map formation is failing. The following is the code. I am using a PDF to create this to help myself learn React.js, but the PDF is unclear. Can I attach the PDF?
This is menu.js
import React from "react"
import MenuItem from "../MenuItem"
export default class Menu extends React.Component {
render() {
return (
<div><h1>{this.props.menuName} Menu</h1>
<MenuItem {...this.props.menuItems[0]}></MenuItem>
<MenuItem {...this.props.menuItems[1]}></MenuItem>
<MenuItem {...this.props.menuItems.map((item) => <p>item</p>)}></MenuItem>
</div>
)
}
This is app.js
import "./App.css"
import MenuApp from "./components/MenuApp"
// let data = {...} (include the data array from above).
function App() {
let menuData = [
{
menuName: "Dinner",
menuItems: [
{
itemId: 1,
itemPrice: "12",
itemName: "Lasagne",
itemDescription:
"Meat and cheese layered between house-made pasta with bell peppers and onions.",
},
{
itemId: 2,
itemPrice: "10",
itemName: "Cheese Ravioli",
itemDescription: "Cheese-filled ravioli served with house red sauce.",
},
{
itemId: 3,
itemPrice: "14",
itemName: "Chicken Parmesan",
itemDescription:
"Breaded chicken topped with marinara sauce and lots of cheese served over house made spaghetti.",
},
]
}]
return (
<div className="App">
<MenuApp data={menuData}></MenuApp>
</div>
)
}
export default App
This is MenuApp.js
import "../../App.css"
import Menu from "../Menu"
function MenuApp() {
return (
<div className="App">
<Menu
menuName="Dinner"
menuItems={[
{
itemId: 1,
itemPrice: "12",
itemName: "Lasagne",
itemDescription:
"Meat and cheese layered between house-made pasta with bell peppers and onions.",
},
{
itemId: 2,
itemPrice: "10",
itemName: "Cheese Ravioli",
itemDescription: "Cheese-filled ravioli served with house red sauce.",
},
{
itemId: 3,
itemPrice: "14",
itemName: "Chicken Parmesan",
itemDescription:
"Breaded chicken topped with marinara sauce and lots of cheese served over house made spaghetti.",
},
]}
></Menu>
</div>
)
}
export default MenuApp
This is MenuItem.js
import React from "react"
export default class MenuItem extends React.Component {
render() {
return (
<div>
<span>${this.props.itemPrice}</span>
<h2>{this.props.itemName}</h2>
<p>{this.props.itemDescription}</p>
<button>Add to Cart</button>
</div>
);
}
}

It seems you are trying to render a variable number of <MenuItem /> components, in which case please try the below in Menu.js.
import React from "react";
import MenuItem from "../MenuItem";
export default class Menu extends React.Component {
render() {
return (
<div>
<h1>{this.props.menuName} Menu</h1>
{this.props.menuItems.map((item) => (
<MenuItem {...item} />
))}
</div>
);
}
}

There can be at least two problems here that are directly linked with what you might get.
Check that you are in fact passing menuItems as a property to Menu component, if it is undefined it will throw TypeError: can't access property "map" of undefined
Looking twice at the code, I noticed that you a de-structuring the result of
this.props.menuItems.map((item) => <p>item</p>) which would result in an incorrect mapping.
Depending on your ECMAScript version, replacing this line as-is would do.
{this.props.menuItems?.map((item) => <p>item</p>)}

Related

Ho to map through mui icons to redirect to url like github/project-url

//i have a separate project file of the projectlist as an array with object, which have the necessary links that i need to map through.
//I just need some help with adding them into the github icon and when a user clicks they can navigate through to the appropriate links from the projectlist. I realise i need to use Object.entries(obj).map(). However, none of the methods i have attempted so far have worked. I am new to react so this may be simpler than I am actually making it. All help is appreciated.
import { useParams } from "react-router-dom";
import { ProjectList } from "../helpers/ProjectList";
import GitHubIcon from "#mui/icons-material/GitHub";
import LanguageIcon from "#mui/icons-material/Language";
import "../styles/ProjectDisplay.css";
//useParams returns an object key/value pairs of the dynamic params from the current URL that were matched by the <Route path>
function ProjectDisplay() {
const { id } = useParams();
const project = ProjectList[id];
return (
<div className="project">
<h1>{project.name}</h1>
<img src={project.image} alt="portfolio-projects" />
<p>
<b>Skills:</b>
{project.skill}
</p>
<GitHubIcon />
<LanguageIcon />
</div>
);
}
export default ProjectDisplay;
*//projectlist below*
export const ProjectList = [
{
name: "SquareSpace Website Homage",
image: squarespace,
skill: "HTML, CSS, JavaScript",
github: "https://github.com/LouisNzavi/Portoflio-Website",
website: "https://mysquarespacehomage.netlify.app/",
},
{
name: "HarryPorter theme TODO CRUD app",
image: harryporter,
skill: "HTML, CSS, JavaScript",
github: "https://github.com/LouisNzavi/TO-DO-APP",
website: "https://gabriellatodoapp.netlify.app/",
},
{
name: "Restaurant Reservation System",
image: reservation,
skill: "React, Redux Toolkit and TypeScript",
github:
"https://github.com/LouisNzavi/RestaurantReservation---reduxToolkit-Typescrpt",
},
{
name: "Deposit/Withdraw system",
image: depositWithdraw,
skill: "React, JavaScript, Redux: reducers/store/action-creators",
github: "https://github.com/LouisNzavi/React-with-redux-deposit-withdraw-",
},
{
name: "Four-card landing page feature",
image: fourcardfeature,
skill: "HTML, CSS, JavaScript",
github: "https://github.com/LouisNzavi/Four-card-feature-design-file",
},
{
name: "Vancouver Sleep Clinc website",
image: vancouver,
skill: "HTML, CSS",
github: "https://github.com/LouisNzavi/Vancouver-Sleep-Clinc-PROJ",
},
{
name: "Intro component with SignUp form",
image: signupForm,
skill: "HTML, CSS, JavaScript",
github: "https://github.com/LouisNzavi/Intro-Signup-form",
},
];
I think this is you want to do
import { useParams } from "react-router-dom";
import { ProjectList } from "../helpers/ProjectList";
import GitHubIcon from "#mui/icons-material/GitHub";
import LanguageIcon from "#mui/icons-material/Language";
import "../styles/ProjectDisplay.css";
//useParams returns an object key/value pairs of the dynamic params from the current URL that were matched by the <Route path>
function ProjectDisplay() {
const { id } = useParams();
const project = ProjectList[id];
return (
<React.Fragment>
{ProjectList.map((project, index) =>
<div key={index} className="project">
<h1>{project.name}</h1>
<img src={project.image} alt="portfolio-projects" />
<p>
<b>Skills:</b>
{project.skill}
</p>
<a href={project.github} rel="noopener noreferrer" target="_blank">
<GitHubIcon />
</a>
<LanguageIcon />
</div>
)}
</React.Fragment>
);
}
export default ProjectDisplay;
You can map your array to the component which will return an array of project components then you can directly render it. I am assuming you are using import to use images in project.name.

Use const from another file in Reactjs

I have an object:
import React, {Component} from 'react';
import ProgressBar from "./ProgressBar";
class Languages extends Component {
state = {
languages: [
{id: 1, value: "XXX", xp: 1.5},
{id: 2, value: "CCC", xp: 1},
{id: 3, value: "AAA", xp: 2}
]
}
render() {
let {languages} = this.state;
const levels = ['Test', 'Bad', 'Sorry']
return (
<div className="languages">
<ProgressBar
programming={languages}
className="languagesDisplay"
levels={levels}
title="Languages"
/>
</div>
);
}
}
export default Languages;
import React from 'react';
const ProgressBar = (props) => {
return (
<div className={props.className}>
<h3>{props.title}</h3>
<div className="years">
<span>Experiences</span>
props.levels.map((level) => {
<span>level</span>
})
</div>
<span>level</span> return props.levels.map((level) =>level)
how can i display the const ['Test', 'Bad', 'Sorry'] from Languages.js in a <span> in a different React file?
Edit after seeing your response above: If the issue is just that the above code isn't working, here are a couple of things to check.
Inside of ProgressBar you've got a couple of errors in your JSX. First, you need curly braces around your JavaScript interpolation and secondly, you're not returning anything in your .map() function. If you were using parentheses it would be an implicit return, but with the curly braces you need a return statement. Try this instead:
import React from 'react';
const ProgressBar = (props) => {
return ( <div className={props.className}>
<h3> {props.title} </h3>
<div className ="years">
<span> Experiences </span>
{props.levels.map((level) => {
return (<span>{level}</span>)
})
} </div>
)};
My initial answer, which still may be helpful for understanding what's going on:
It's not entirely clear what you want to do, but here are a couple of things that might be helpful.
What's happening in your code above is that the levels variable, which is an array of strings, is being passed down from the parent component Languages into the child component ProgressBar via the props object.
When ProgressBar is called inside of Languages, it's properties (or props) are set (programming, className, levels, title).
The levels={levels} part means that the prop levels on ProgressBar is being set to the variable levels (the array of strings).
Inside of ProgressBar all of those properties are accessible in the props object that's passed as an argument. That's why you're able to access that array of strings with props.levels.map() which will map the array of strings however you tell it to (in this case by printing each individual item within a <span> tag).
So, with that understanding of what's happening here, here are a couple of things you could do to access the levels variable elsewhere in another file.
If levels is a constant that you want to access in multiple places, you could move it outside of the body of your Languages component and export it to use it in other places.
That could look like:
import React, {
Component
} from 'react';
import ProgressBar from "./ProgressBar";
export const levels = ['Test', 'Bad', 'Sorry']
class Languages extends Component {
state = {
languages: [{
id: 1,
value: "XXX",
xp: 1.5
},
{
id: 2,
value: "CCC",
xp: 1
},
{
id: 3,
value: "AAA",
xp: 2
}
]
}
render() {
let {
languages
} = this.state;
return ( <
div className = "languages" >
<
ProgressBar programming = {
languages
}
className = "languagesDisplay"
levels = {
levels
}
title = "Languages" /
>
<
/div>
);
}
}
export default Languages;
By exporting it from the top level, you could import it in another file exactly as it is.
import { levels } from '/insert-first-file-location-here'
Another option is to pass the levels variable into another component as a prop. This way if levels gets changed at the top level, those changes will drill down into subsequent components.
import React, {Component} from 'react';
import ProgressBar from "./ProgressBar";
class Languages extends Component {
state = {
languages: [
{id: 1, value: "XXX", xp: 1.5},
{id: 2, value: "CCC", xp: 1},
{id: 3, value: "AAA", xp: 2}
]
}
render() {
let {languages} = this.state;
const levels = ['Test', 'Bad', 'Sorry']
return (
<>
<div className="languages">
<ProgressBar
programming={languages}
className="languagesDisplay"
levels={levels}
title="Languages"
/>
</div>
<AnotherComponentThatUsesLevels
levels={levels} />
</>
);
}
}
export default Languages;
And then
import React from 'react'
export const AnotherComponentThatUsesLevels (props) => {
return (
<>
{/* do something with levels here, maybe map them like before*/}
{props.levels.map((level) => (<span>{level}</span>)}
</>
)
}
Does that help understand what's happening in the example and give you a couple of ways you could use that variable in another location?
You need to export that certain constant from your file like that:
import React, {
Component
} from 'react';
import ProgressBar from "./ProgressBar";
export const levels = ['Test', 'Bad', 'Sorry']
class Languages extends Component {
state = {
languages: [{
id: 1,
value: "XXX",
xp: 1.5
},
{
id: 2,
value: "CCC",
xp: 1
},
{
id: 3,
value: "AAA",
xp: 2
}
]
}
render() {
let {
languages
} = this.state;
return (
<div className="languages">
<ProgressBar
programming={languages}
className="languagesDisplay"
levels={levels}
title="Languages"
/>
</div>
);
}
}
export default Languages;
After it, you need to import it in the file where you want to access it:
import {levels} from '/path/to/file';

I am having an issue with integrating an existing react component I found, into my app. "Attempted import error:"

My goal is to bring an existing react component (below) that I found on the web, into my app to use. It is an animated navigation bar.
Here is the error message I receive after trying to compile the below code (snippets 2 and 3 below):
Failed to compile.
./src/components/Navbar.js
Attempted import error: 'react-responsive-animate-navbar' does not contain a default export (imported as 'ReactNavbar').
Maybe there is an issue with the library I installed? The creator had made this component 7 months ago, here - https://www.npmjs.com/package/react-responsive-animate-navbar.
Regardless, please see below for details on 1. the component I am trying to bring in, 2. the component in my code, refactored slightly and 3. the file I am importing this component into.
This is the component I found on the web. It renders an awesome navbar I would like to bring into my app. HOWEVER, I have never used the "class ... extends compoent" syntax. I have only used the "export default function name(){return()}" style.
npm install --save react-responsive-animate-navbar
import React from "react";
import ReactNavbar from "react-responsive-animate-navbar";
class Example extends Component {
render() {
return (
<ReactNavbar
color="rgb(25, 25, 25)"
logo="https://svgshare.com/i/KHh.svg"
menu={[
{ name: "HOME", to: "/" },
{ name: "ARTICLES", to: "/articles" },
{ name: "ABOUT ME", to: "/about" },
{ name: "CONTACT", to: "/contact" },
]}
social={[
{
name: "Linkedin",
url: "https://www.linkedin.com/in/nazeh-taha/",
icon: ["fab", "linkedin-in"],
},
{
name: "Facebook",
url: "https://www.facebook.com/nazeh200/",
icon: ["fab", "facebook-f"],
},
{
name: "Instagram",
url: "https://www.instagram.com/nazeh_taha/",
icon: ["fab", "instagram"],
},
{
name: "Twitter",
url: "http://nazehtaha.herokuapp.com/",
icon: ["fab", "twitter"],
},
]}
/>
);
}
}
Here is the component since I have brought it into my app and slightly refactored it to fit the react syntax I have been using.
./src/components/Navbar.js
import React from "react";
import ReactNavbar from "react-responsive-animate-navbar";
export default function Navbar({ setSignedIn }) {
return (
<ReactNavbar
color="rgb(25, 25, 25)"
logo="https://svgshare.com/i/KHh.svg"
menu={[
{ name: "HOME", to: "/Explore" },
{ name: "ARTICLES", to: "/articles" },
{ name: "My Profile", to: "/profile" },
{ name: "CONTACT", to: "/contact" },
]}
social={[
{
name: "Linkedin",
url: "https://www.linkedin.com/in/nazeh-taha/",
icon: ["fab", "linkedin-in"],
},
{
name: "Facebook",
url: "https://www.facebook.com/nazeh200/",
icon: ["fab", "facebook-f"],
},
{
name: "Instagram",
url: "https://www.instagram.com/nazeh_taha/",
icon: ["fab", "instagram"],
},
{
name: "Twitter",
url: "http://nazehtaha.herokuapp.com/",
icon: ["fab", "twitter"],
},
]}
/>
);
}
And finally, here is where I am attempting to import this component for it to render onto an actual page.
./src/Pages/IntroPage
import React from "react";
import Navbar from "../components/Navbar";
import Categories from "../components/Categories";
export default function ChooseACategory({ setSignedIn }) {
return (
<div>
<Navbar setSignedIn={setSignedIn} />
<Categories />
</div>
);
}
I suspect the issue is with my refactoring from the "class ... extends component" syntax to the "export default function name" syntax (which I am more familiar with). I understand there is not a big difference between the two, but I would rather keep my code for this project uniform. Any help is welcome!
There was nothing wrong with you refactor, because you did not use any states. I installed that package, with nothing changed. The same wrong message as yours appeared when I started it. I suspect this package itself is not runnable.
Looking at the source for that package, it does not contain a default export. It has:
export const ReactNavbar without the default.
Try importing the named component instead of as a default:
import { ReactNavbar } from instead of import ReactNavbar from
For my situation, I found a workaround solution, it not renders and works properly using the highlighted edit in the screenshot below. Thanks!
import React from "react";
import * as ReactNavbar from "react-responsive-animate-navbar";
import Logo from "../Assets/Media/ToolioLogoSmall.png"
export default function Navbar({ setSignedIn }) {
console.log(ReactNavbar.ReactNavbar) //Edited, fixed issue.
return (
<div style={style.background}>
<ReactNavbar.ReactNavbar style={style.background}
color="rgb(25, 25, 25)"
logo={Logo}
menu={[
{ name: "HOME", to: "/Explore" },
{ name: "ARTICLES", to: "/articles" },
{ name: "My Profile", to: "/profile" },
{ name: "CONTACT", to: "/contact" },
]}
social={[
{
name: "Linkedin",
url: "https://www.linkedin.com/",
icon: ["fab", "linkedin-in"],
},
{
name: "Facebook",
url: "https://www.facebook.com/",
icon: ["fab", "facebook-f"],
},
{
name: "Instagram",
url: "https://www.instagram.com/",
icon: ["fab", "instagram"],
},
{
name: "Twitter",
url: "http://www.twitter.com/",
icon: ["fab", "twitter"],
},
]}
/>
</div>
);
}

Image not showing up on Page

I'm making a portfolio website, and I'm trying to make logo images show up, but they're not showing up.
Originally, I had the content in the this.state in HomePage.js, but I decided it would be neater to put it in a different file. The images showed up when they were in HomePage.js.
Relevant Code
HomePageContent.js
// Image import statements
import Image1 from '../img/Image1.jpg';
import Image2 from '../img/Image2.jpg';
let HomePageContent = {
jobs: [{
logo: {Image1},
companyName: 'Company1' ,
title: 'Job1',
startMonth: 'November 2019',
endMonth: 'Present',
location: 'Location1',
desc: 'Placeholder',
id: 1
}, {
logo: {Image2},
companyName: 'Company2',
title: 'Job2',
startMonth: 'June 2018',
endMonth: 'May 2019',
location: 'Location2',
desc: 'Placeholder',
id: 2
}]};
export default HomePageContent;
HomePage.js
import React from 'react';
// Component import statements
import JobsList from '../components/JobsList.js';
// Content import Statements
import HomePageContent from '../content/JobsContent.js';
class Home extends React.Component {
constructor(props) {
super(props);
this.state = HomePageContent;
}
render() {
return(
<div>
<h4>Here's what I've done</h4>
<JobsList jobs={this.state.jobs}/>
</div>
)
}
}
export default Home;
JobsList.js
import React from "react";
import Jobs from "./Jobs";
function JobsList(props) {
return (
<div className="JobsList">
{props.jobs.map(j =>
<Jobs logo={j.logo}
companyName={j.companyName}
title={j.title}
startMonth={j.startMonth}
endMonth={j.endMonth}
location={j.location}
desc={j.desc}key={j.id}/>
)}
</div>
);
}
export default JobsList;
Jobs.js
import React from 'react';
import '../css/Experience.css';
function Jobs(props) {
console.log(props.name);
return (
<div className='exp-container'>
<img src={props.logo} alt='Logo' />
<div className='content'>
<div>{props.companyName}</div>
<div>{props.title}</div>
<div>{props.startMonth} - {props.endMonth}</div>
<div>{props.location}</div>
<div><p>{props.desc}</p></div>
</div>
</div>
);
}
export default Jobs;
<img src={props.logo} alt='Logo' />
You are trying to read the image from the logo property. (Aside: Your alt text isn't useful).
logo: {Image1},
… but the value of the logo property isn't an image. It is another object. That object has a property named Image1 and the value of that property is an image.
Don't create an extra object; just assign the image to the logo property:
logo: Image1,

Map stops iterating after first iteration in React

My component is supposed to retrieve the data for courses when the component mounts. The problem that I have is that whether I use the course Id or the course title as the key, I get the following error:
index.js:1 Warning: Each child in a list should have a unique "key" prop.
I have looked through the react docs, here on Stack Overflow, and tried different ways to get it to work. The only way I can get it to partially work is by adding an index as a parameter for map. When I use this method, I run into another problem and that is, it stops after the first iteration, even though there are 10 items. How can I fix this?
Here is my code:
CoursesPage.js
import React from 'react';
import { connect } from 'react-redux';
import * as courseActions from '../../redux/actions/courseActions';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
class CoursesPage extends React.Component {
componentDidMount() {
this.props.actions.loadCourses().catch(error => {
alert("Loading courses failed" + error);
});
}
render() {
return (
<>
<h2>Courses</h2>
{this.props.courses.map((course, index) => (
<div key={course[index].title}>{course[index].title}</div>
))}
</>
);
}
}
CoursesPage.propTypes = {
courses: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
}
function mapStateToProps(state) {
return {
courses: state.courses
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(courseActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CoursesPage);
My mock data:
const courses = [
{
id: 1,
title: "Securing React Apps with Auth0",
slug: "react-auth0-authentication-security",
authorId: 1,
category: "JavaScript"
},
{
id: 2,
title: "React: The Big Picture",
slug: "react-big-picture",
authorId: 1,
category: "JavaScript"
},
{
id: 3,
title: "Creating Reusable React Components",
slug: "react-creating-reusable-components",
authorId: 1,
category: "JavaScript"
},
{
id: 4,
title: "Building a JavaScript Development Environment",
slug: "javascript-development-environment",
authorId: 1,
category: "JavaScript"
},
{
id: 5,
title: "Building Applications with React and Redux",
slug: "react-redux-react-router-es6",
authorId: 1,
category: "JavaScript"
},
{
id: 6,
title: "Building Applications in React and Flux",
slug: "react-flux-building-applications",
authorId: 1,
category: "JavaScript"
},
{
id: 7,
title: "Clean Code: Writing Code for Humans",
slug: "writing-clean-code-humans",
authorId: 1,
category: "Software Practices"
},
{
id: 8,
title: "Architecture Applications for the Real World",
slug: "architecting-applications-dotnet",
authorId: 1,
category: "Software Architecture"
},
{
id: 9,
title: "Becoming an Outlier: Reprogramming the Developer Mind",
slug: "career-reboot-for-developer-mind",
authorId: 1,
category: "Career"
},
{
id: 10,
title: "Web Component Fundamentals",
slug: "web-components-shadow-dom",
authorId: 1,
category: "HTML5"
}
];
const authors = [
{ id: 1, name: "Cory House" },
{ id: 2, name: "Scott Allen" },
{ id: 3, name: "Dan Wahlin" }
];
const newCourse = {
id: null,
title: "",
authorId: null,
category: ""
};
module.exports = {
newCourse,
courses,
authors
};
Edit:
I am using Redux Thunk.
Here is my actionType.js file:
export const CREATE_COURSE = "CREATE_COURSE";
export const LOAD_COURSES_SUCCESS = "LOAD_COURSES_SUCCESS";
Here is my CourseActions.js file:
import * as types from './actionTypes';
import * as courseApi from "../../api/courseApi";
export function createCourse(course) {
return { type: types.CREATE_COURSE, course };
}
export function loadCourseSuccess(courses) {
return { type: types.LOAD_COURSES_SUCCESS, courses };
}
export function loadCourses() {
return function (dispatch) {
return courseApi.getCourses().then(courses => {
dispatch(loadCourseSuccess(courses));
}).catch(error => {
throw error;
})
}
}
Here is my courseReducer.js file:
import * as types from '../actions/actionTypes';
export default function courseReducer(state = [], action) {
switch (action.type) {
case types.CREATE_COURSE:
return [...state, { ...action.course }];
case types.LOAD_COURSES_SUCCESS:
return [...state, { ...action.courses }];
default:
return state;
}
}
Any help would be appreciated.
Thanks.
P.S. I know that you should use Id for key. But the way it has to be done for now is using the title of the course as the key.
With your edits, I think we can more effectively help you. For future, it would be beneficial to post an example of your code not working on https://codesandbox.io/
Also to help yourself out when you debug, isolate the react component from the use of redux. This will allow you to ensure your react component renders when given data, then focus on getting redux to provide you the data your react component has.
You can do this by first defining mockdata inside your react component, then moving that mock data to your reducer, then finally replacing the mock data with the live api call.
On to the code:
You have two issues: the first is that you want to index into the array courses but instead due to a typo, you are actually using the property accessor into the object course
key={course[index].title}
As your question states you must use the title as the key simply change the div to be:
<div key={course.title}>{course.title}</div> and your code should work as expected.
Once you have addressed that, then re-enable loading data from your API call using Redux, and you can address the issues with Redux.
Looking at your reducer, you have a clear bug, and depending on your use case, a potential bug:
case types.LOAD_COURSES_SUCCESS:
return [...state, { ...action.courses }];
action.courses is an array, and the code is creating a new array that contains all the elements of the previous array state and adding a new object, which contains the contents of a destructured array.courses array.
Which that does is effectively append a single object to your array, and the object is comprised of elements from your courses array. The item index becomes the key, and the item itself is the value.
You can visualize it here: https://codesandbox.io/s/divine-pond-nr3j8
Instead you want
return [...state, ...action.courses];
The second, potential bug, is that you are actually appending the results of the courses api. Which for subsequent calls to load courses, you will duplicate the data. That may be what you want, but I am going to assume that is not what you want.
So instead, your LOAD_COURSES_SUCCESS case should be rewritten to simply be:
return [...action.courses];
Since each course has a unique ID field, the problem could be solved by using the id as a key
render() {
return (
<>
<h2>Courses</h2>
{this.props.courses.map(course => (
<div key={course.id}>{course.title}</div>
))}
</>
);
}
The issue is here:
{this.props.courses.map((course, index) => (
<div key={course[index].title}>{course[index].title}</div>
))}
//course in itself is data
Solution:
{this.props.courses.map((course, index) => (
<div key={`${course.title}-${index}`}>{course.title}</div>
))}
Better way would always to take care unique id for key
Here's the code snippet for render method.
Give it a try.
*Update = use course title as key
render() {
const courseList = this.props.courses.map(course => (
<div key={course.title}></div>
));
return (
<>
<h2>Courses</h2>
<div>{courseList}</div>
</>
);
}
There are many ways you can pass the key when it is iterating...
var courses = this.state.courses.map(function(course, index) {
return(
<div key={index}>
<div key={course.title} id={course.title}>
<h2 key={"header"+course.title}>{course.title}</h2>
</div>
</div>
)
});
But you should try to pass a unique id rather than a string.

Categories