from an array inside an object and renders it to the browser. The App uses a number of small components Header, Contents and Total to function.
Next part of exercise is to create a single component 'Course' to do the same job as all the smaller components(Header,Contents,Total)
Here is original app that gives this output:
Half Stack application development
Fundamentals of React10
Number of exercises is 31
import React from 'react'
const Header = (props) => {
return (
<div>
<h1>{props.course}</h1>
</div>
)
}
const Content = (props) => {
return (
<div>
<p>{props.part1}</p>
</div>
)
}
const Part = (props) => {
return (
<div>
<p>{props.part1} {props.exercises1}</p>
</div>
)
}
const Total = (props) => {
return (
<div>
<p>Number of exercises is {props.total}</p>
</div>
)
}
const App = () => {
const course = {
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10
},
{
name: 'Using props to pass data',
exercises: 7
},
{
name: 'State of a component',
exercises: 14
}
]
}
return (
<div>
<Header course={course.name} />
<Content part1 = {course.parts[0].name + course.parts[0].exercises} />
<Total total = {course.parts[0].exercises + course.parts[1].exercises + course.parts[2].exercises} />
</div>
)
}
export default App
And here is the new component I created which is giving me a blank output, no errors reported
const Course = (props) => {
return (
<div>
<Header></Header>
<Content></Content>
<Total></Total>
</div>
)
}
With updated App
onst App = () => {
const course = {
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10
},
{
name: 'Using props to pass data',
exercises: 7
},
{
name: 'State of a component',
exercises: 14
}
]
}
return <Course course={course} />
}
export default App
Related
I'm new to React and programing in general and I'm having trouble writing code that return each element in an array, in React JS.
the whole code is below:
import React from 'react'
const App = () => {
const course = {
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10
},
{
name: 'Using props to pass data',
exercises: 7
},
{
name: 'State of a component',
exercises: 14
}
]
}
const Header = (props) => {
return (
<h1>{props.course.name}</h1>
)
}
const Content = (props) => {
const lisItem = props.course.parts.map((part =>
<li>{props.course.parts.name}</li>
))
return (
<ul>{lisItem}</ul>
)
}
return (
<div>
<Header course={course}/>
<Content course={course}/>
</div>
)
}
export default App
Right now it half-works: I can display 3 bullet points (match with numbers of parts) but cannot display the name of the part itself.
Also I would like to clarify the out put a wanted is the course's name and each name of the parts be displayed.
Any help would be appreciated. Thank you very much.
You are not using map correctly. It should be like this:
const lisItem = props.course.parts.map((part) => <li>{part.name}</li>);
You were ignoring each part given to you by map. Check docs of map.
Also I see now you were defining the two components Header and Content inside the App component, that is not good practice (due to reconciliation), move their definition outside of App:
import React from "react";
const Header = (props) => {
return <h1>{props.course.name}</h1>;
};
const Content = (props) => {
const lisItem = props.course.parts.map((part) => <li>{part.name}</li>);
return <ul>{lisItem}</ul>;
};
const App = () => {
const course = {
name: "Half Stack application development",
parts: [
{
name: "Fundamentals of React",
exercises: 10,
},
{
name: "Using props to pass data",
exercises: 7,
},
{
name: "State of a component",
exercises: 14,
},
],
};
return (
<div>
<Header course={course} />
<Content course={course} />
</div>
);
};
Your .map( part => ...) iterates props.course.parts, the part inside the map function is a single item of the list.
Check MDN for more info https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
I have some CMS content being returned and my goal is to have a year slider controlling the content depending on the year that the user selects by clicking the minus/plus arrow.
This is my code:
import "./styles.css";
import React from "react";
export default function App() {
return (
<div className="App">
<DatesProvider>
{data.map((item, index) => {
const Slice = slices[item.type];
return <Slice section={item.section} key={index} />;
})}
</DatesProvider>
</div>
);
}
const DateContext = React.createContext({});
const DatesProvider = ({ children }) => {
const [dates, setDates] = React.useState({});
return (
<DateContext.Provider value={{ dates, setDates }}>
{children}
</DateContext.Provider>
);
};
const DatePicker = ({ section }) => {
const { dates, setDates } = React.useContext(DateContext);
React.useEffect(() => {
// Set initial date
setDates((prevDates) => {
prevDates[section] = 2021;
return { ...prevDates };
});
// Clean up on dismount
return () => {
setDates((prevDates) => {
delete prevDates[section];
return { ...prevDates };
});
};
}, []);
const handlePlus = () => {
setDates((prevDates) => ({
...prevDates,
[section]: prevDates[section] + 1
}));
};
const handleMinus = () => {
setDates((prevDates) => ({
...prevDates,
[section]: prevDates[section] - 1
}));
};
return (
<div style={{ marginTop: 30 }}>
<button onClick={handleMinus}>-</button>
<span>{dates[section]}</span>
<button onClick={handlePlus}>+</button>
</div>
);
};
const Item = ({ section }) => {
const { dates } = React.useContext(DateContext);
return (
<div>
Section: {section} | Year: {dates[section]}
</div>
);
};
const data = [
{ type: "DatePicker", section: "foo" },
{ type: "Item", section: "foo" },
{ type: "Item", section: "foo" },
{ type: "DatePicker", section: "bar" },
{ type: "Item", section: "bar" },
{ type: "Item", section: "bar" }
];
const slices = { DatePicker, Item };
The result is currently this:
As you can tell it's returning the year slider several times and the structure is similar to this:
<slider> - 2021 + </slider>
<section class= "container-of-all-items">
<all-items></all-items>
</section>
<slider> - 2021 + </slider>
<section class= "container-of-all-items">
<all-items></all-items>
</section>
My goal is to have only one year slider wrapping/controlling the whole content items rather than the above repetition of sliders:
<slider> - 2021 + </slider>
<section class= "container-of-all-items">
<all-items></all-items>
</section>
Any idea how to achieve it by maintaining a map through the Slices?
I see, took me a while to understand, you basically want to have one set of + and - but list of items.
Then in your case, you code actually simplifies.
function Lists() {
const { dates, setDates } = React.useContext(DateContext);
const onClick = () => { setDates(...) }
return (
<>
<div onClick={onClick}>+</div>
<>
{dates.map((item, index) => {
return <Slice section={item.section} key={index} />
})}
</>
<div>-</div>
</div>
);
}
Then change your App.
export default function App() {
return (
<div className="App">
<DatesProvider value={...}>
<Lists />
</DatesProvider>
</div>
);
}
Actually you might not need the context at all, since the logic has been promoted to the parent. But it's up to you.
I have a react js code in a magento pwa app.
It has a component called categoryList and I need to add a horizontal scroll menu for that category list.
Following is my code
const mapCategory = categoryItem => {
const { items } = categoryItem.productImagePreview;
return {
...categoryItem,
productImagePreview: {
items: items.map(item => {
const { small_image } = item;
return {
...item,
small_image:
typeof small_image === 'object'
? small_image.url
: small_image
};
})
}
};
};
const list = [
{ name: 'item1' },
{ name: 'item2' },
{ name: 'item3' },
{ name: 'item4' },
{ name: 'item5' },
{ name: 'item6' },
{ name: 'item7' },
{ name: 'item8' },
{ name: 'item9' }
];
const MenuItem = ({ text, selected }) => {
return (
<div
className="menu-item"
>
{text}
</div>
);
};
export const Menu = (list) => list.map(el => {
const { name } = el;
return (
<MenuItem
text={name}
key={name}
/>
);
});
const Arrow = ({ text, className }) => {
return (
<div
className={className}
>{text}</div>
);
};
const ArrowLeft = Arrow({ text: '<', className: 'arrow-prev' });
const ArrowRight = Arrow({ text: '>', className: 'arrow-next' });
const CategoryList = props => {
const { id, title } = props;
const talonProps = useCategoryList({
query: categoryListQuery,
id
});
const { childCategories, error, loading } = talonProps;
const classes = mergeClasses(defaultClasses, props.classes);
console.log('ssss' +childCategories);
const header = title ? (
<div className={classes.header}>
<h2 className={classes.title}>
<span>{title}</span>
</h2>
</div>
) : null;
let child;
if (error) {
child = (
<div className={classes.fetchError}>
Data Fetch Error: <pre>{error.message}</pre>
</div>
);
}
if (loading || !childCategories) {
child = fullPageLoadingIndicator;
} else if (childCategories.length === 0) {
child = (
<div className={classes.noResults}>No child categories found.</div>
);
} else {
const { selected } = this.state;
// Create menu from items
const menu = Menu(list, selected);
child = (
<div className={classes.content}>
{childCategories.map((item, index ) => (
<CategoryTile item={mapCategory(item)} key={index} />
))}
<ScrollMenu data={menu}
arrowLeft={ArrowLeft}
arrowRight={ArrowRight}
onSelect=''
/>
</div>
);
}
return (
<div className={classes.root}>
{header}
{child}
</div>
);
};
CategoryList.propTypes = {
id: number,
title: string,
classes: shape({
root: string,
header: string,
content: string
})
};
export default CategoryList;
I get the following error when I try to use this code. The error seems to be about not being to resolve a specific package or module.
ERROR in ./src/components/CategoryList/categoryList.js
Module not found: Error: Can't resolve 'react-horizontal-scrolling-menu/build/scrollMenu' in '/var/www/html/apekade/apekade-pwa/packages/pwa-neosolax/src/components/CategoryList'
ℹ 「wdm」: Failed to compile.
I dont know if I have placed the code correct.I'm a beginner.Please help
Running a simple "npm install --update --save" worked for me, after struggling for an hour to resolve this issue.
This usually means that the particular package/dependency (in this case "react-horizontal-scrolling-menu") is not installed
you can install it by using "npm install react-horizontal-scrolling-menu" or "yarn add react-horizontal-scrolling-menu"
If you are working on a project then you can go to 'package.json' and add "react-horizontal-scrolling-menu": "^2.7.1" or any other version u need and then go to the terminal and type "npm install --legacy-peer-deps"
I created a CodeSandbox so I can elaborate my question.
I would like to ask for your suggestion on my Project:
I currently have a website portfolio app that are divided into 4 pages:
Loading.js directly fetch -> Home.js
About.js
Contact.js
Work.js – it displays a link of my projects that will open a Sliding Sidebar/Side Drawer
feature.
What I wanted to do is to fetch the individual project components and pass it in the Sliding Sidebar once a specific project was clicked by the user.
My question is what is the best way to manage the state? how do I pass the props from the project that was clicked and display the specific project component from the components folder?
CodeSandbox Link <----
updated work.js
import React, { useState } from "react";
import StyledWorkNav from "./StyledWorkNav";
import SideDrawer, { StyledDrawer } from "./SideDrawer";
import Project1 from "./components/Project1";
import Project2 from "./components/Project2";
import Project3 from "./components/Project3";
const Work = () => {
const [drawerOpen, setDrawerOpen] = useState(false);
const [projects, setProjects] = useState([
{ name: 'Project 1', projId: '1', dataText: 'Proj 1', comp:"" },
{ name: 'Project 2', projId: '2', dataText: 'Proj 2', comp:"Project2" },
{ name: 'Project 3', projId: '3', dataText: 'Proj 3', comp:"Project3" },
]);
const [selectedProject, setSelectedProject] = useState(null);
const strToComponent = {
Project1: <Project1/>,
Project2: <Project2/>,
Project3: <Project3/>
}
const openDrawerHandler = () => {
if (!drawerOpen) {
setDrawerOpen(true);
} else {
setDrawerOpen(false);
}
};
const closeDrawerHandler = () => {
setDrawerOpen(false);
};
// -------------------****** update **************
let drawer;
if (drawerOpen) {
drawer = (
<SideDrawer
close={closeDrawerHandler}
sidebar={{ StyledDrawer }}
// pass down here one of the wanted component : project1.js, 2 etc..
project={
<Project1
selectedProject={selectedProject} // you can pass the selected
// project as prop for
// project1.js for example
/>
}
/>
);
}
return (
<StyledWorkNav>
<ul>
{projects.map((project) => (
<li
key={project.projId}
onClick={() => {
setSelectedProject(project);
openDrawerHandler();
}}>
<p data-text={project.dataText}>{project.name}</p>
</li>
))}
{selectedProject && drawer}
</ul>
</StyledWorkNav>
);
};
export default Work;
you can do something like this :
Upadate
imports ......
// this state will contain all your projects
const [projects, setProjects] = useState([
{
id: 1,
name: "project1"
},
{
id: 2,
name: "project2"
},
.....
])
// this will contain on of the project selected from the list of
// projects
const [selectedProject, setSelectedProject] = useState({
id: 1,
name: "project1"
})
return (
<>
<List>
{ projects.map(project => (
<ListItem key={project.id} onClick={() => setSelectedProject(project)}>
{project.name}
</ListItem>
))
}
</List>
{
selectedProject &&
<Sidebar // the selected project goes here and change every time a different project selected
project={selectedProject}
/>
}
</>
)
export ......
This question already has an answer here:
forEach() in React JSX does not output any HTML
(1 answer)
Closed 3 years ago.
The issue is that the variable is having the value when I console.log but it is not rendering in the page. The loop print only the first data and other data is not printed.
const langData = [
{
name: "Front-End",
children: [
{
name: "HTML"
},
{
name: "CSS"
},
{
name: "JS"
}
]
}
];
const renderName = ({ name, children }) => {
console.log(name);
return (
<>
<p>{name}</p>
{children && children.forEach(newData => renderName(newData))}
</>
);
};
const App = () => {
return <div className="App">{renderName(langData[0])}</div>;
};
Eg: Front-End will be on the page. Other data such as HTML, CSS, JS not showing in the page. But these variables are in the console.log. Not sure I miss to return any value.
Codesandbox link: https://codesandbox.io/s/reverent-ardinghelli-6snby?fontsize=14
Using map you can get go over the array. The reason why map works and forEach does not is because map returns a new array while forEach does not return anything(returns undefined). You also need to add keys to get rid of the warning. I've used the index of the array as the key here:
const renderName = ({ name, children }, key) => {
console.log(name);
return (
<>
<div key={key}>
<p>{name}</p>
{children && children.map((newData,index) => renderName(newData, index))}
</div>
</>
);
};
with render an array, you should use map, because .forEach always return undefined:
const renderName = ({ name, children, index }) => {
console.log(name);
return (
<div key={index}>
<p>{name}</p>
{children && children.map((item, index)=> {
const { name } = item;
return renderName({name, index})
})}
{/* {children && children.forEach(newData => renderName(newData))} */}
</div>
);
};
Try this you will directly get your result.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const langData = [
{
name: "Front-End",
children: [
{
name: "HTML"
},
{
name: "CSS"
},
{
name: "JS"
}
]
}
];
const renderName = (name,data) => (
//console.log(name);
<>
<p>{name}</p>
{data && data.map(child => (
<p>{child.name}</p>
))}
</>
);
const App = () => {
return <div className="App">{renderName(langData[0].name,langData[0].children)}</div>;
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);