react component iterating over data and mapping a complicated row structure - javascript

Data looks like this:
const items = [
{ image: "http://loremflickr.com/320/320/sport-car?random=1", title: "BMW 545", price: "6.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=2", title: "Mercedes GL", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=3", title: "Toyota", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=4", title: "Porsche", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=5", title: "VW Golf", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=6", title: "Infinity GS", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=7", title: "Ford GT", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=8", title: "Mitsubishi Lancer", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=9", title: "Fiat Punto", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=10", title: "Pegaout Corsa", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=11", title: "Open Corsa", price: "16.500$" },
{ image: "http://loremflickr.com/320/320/sport-car?random=12", title: "VW Passat", price: "16.500$" }
]
final structure should look like this:
<div className="Grid">
<div className="Grid-cell u-size1of2"><Card type="double"/></div>
<div className="Grid-cell u-size1of2"><Card type="double"/></div>
</div>
<div className="Grid">
<div className="Grid-cell u-size1of4"><Card/></div>
<div className="Grid-cell u-size2of4"><Card type="double"/></div>
<div className="Grid-cell u-size1of4"><Card/></div>
</div>
<div className="Grid">
<div className="Grid-cell u-size1of2"><Card type="double"/></div>
<div className="Grid-cell u-size1of2"><Card type="double"/></div>
</div>
<div className="Grid">
<div className="Grid-cell u-size1of4"><Card/></div>
<div className="Grid-cell u-size2of4"><Card type="double"/></div>
<div className="Grid-cell u-size1of4"><Card/></div>
</div>
<div className="Grid">
<div className="Grid-cell u-size1of2"><Card type="double"/></div>
<div className="Grid-cell u-size1of2"><Card type="double"/></div>
</div>
image / title / price can be passed to Card component.
I started by creating a for loop, but that thing very soon started to look like a monstrosity of if/else.
Is it possible to use map for this? or there a better library for handling this kind of templating?

This should deliver the desired DOM grid: http://codepen.io/PiotrBerebecki/pen/rrdBjX
You would now need to clean the code and apply proper styling.
class App extends React.Component {
render() {
const GridArrays = {};
items.forEach((item, index, array) => {
if (index % 5 === 0) {
GridArrays[Object.keys(GridArrays).length] = array.slice(index, index + 2);
} else if (index % 5 === 2) {
GridArrays[Object.keys(GridArrays).length] = array.slice(index, index + 3);
}
});
const renderGrids = Object.keys(GridArrays).map(key => {
if (Number(key) % 2 === 0) {
return <TwoCars cars={GridArrays[key]} />;
} else {
return <ThreeCars cars={GridArrays[key]} />;
}
});
return (
<div>
{renderGrids}
</div>
);
}
}
class TwoCars extends React.Component {
render() {
const renderTwoCars = this.props.cars.map((car, index) => {
return (
<div className="grid-cell u-size1of2">
<Card type="double" image={car.image} title={car.title} price={car.price} />
</div>
);
});
return (
<div className="grid-wrapper">
{renderTwoCars}
</div>
);
}
}
class ThreeCars extends React.Component {
render() {
const renderThreeCars = this.props.cars.map((car, index) => {
return (
<div className={index % 2 === 0 ? "grid-cell u-size1of4" : "grid-cell u-size2of4"}>
<Card image={car.image} title={car.title} price={car.price} type={index % 2 !== 0 ? 'double' : ''} />
</div>
);
});
return (
<div className="grid-wrapper">
{renderThreeCars}
</div>
);
}
}
class Card extends React.Component {
render() {
let style = this.props.type === 'double' ? 'double' : 'single';
return (
<div className={`card-${style}`}>
<div className={`image-${style}`}>
<img className={`img-${style}`} src={this.props.image} />
</div>
<div className={`desc-${style}`}>
<h4>{this.props.title}</h4>
<p>{this.props.price}</p>
</div>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);

If it were me making this application what I'd do is make three more components. A TwoCardRow component and a ThreeCardRow component and then I'd make a container component whose job it is to chop up the array you've got there into groups of two and three respectively in a loop and just pass the appropriate number of array items to those Two and Three card row components.

Related

How to create loop inside React return?

I just learn React so i have a question. I develop the Tic-toe game which is stayed in the official documentation. There are extra-tasks bellow the "Tutorial". One of them is
"Rewrite Board to use two loops to make the squares instead of hardcoding them."
We have this code for generation playing field:
return (
<div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
But we should remake this using any loop. I started to search information about this but found solution only with using map. So now i have code like this:
const mas = Array(3).fill(null)
let i = -1;
return(
<div>
{mas.map(() =>{
return(
<div className = "board-row">
{mas.map(() => {
i+= 1;
return (<span key={i}>{this.renderSquare(i)}</span>);
})}
</div>)
})}
</div>
)
Probably there is another solution of this task... Using for example for loop or something like this...
This is absolutely fine, but another option would be exporting the rows to their own component, this way you would be able to return the following:
{[1,2,3].map((key) => <Row key={key} />)}
And the row component could return the following
{[1,2,3].map((key) => <span key={key}>renderSquare(key)</span>)}
const renderItems = [
{
id: 0
},
{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
},
{
id: 5
},
{
id: 6
},
{
id: 7
},
{
id: 8
},
{
id: 9
}
];
const Board = ({ itemNo }) => {
return <p>{itemNo}</p>;
};
const BoardGame = () => {
return (
<div className='grid cols-3'>
{renderItems.map(item => {
return <Board key={item?.id} itemNo={item?.id} />;
})}
</div>
);
};

How to conditionally group HTML tags in React

I have template rendering in a loop like this
{
category.menuIds.map((menuId, idx) => (
<TemplateMenu
index={idx}
key={menuId}
menu={this.props.menus[menuId]}
menuLayout={category.menu_layout}
/>
));
}
It renders a list of <div> as below:
<div id="m0" class="Menu">...</div>
<div id="m1" class="Menu">...</div>
<div id="m2" class="Menu">...</div>
<div id="m3" class="Menu">...</div>
<div id="m4" class="Menu">...</div>
<div id="m5" class="Menu">...</div>
<div id="m6" class="Menu">...</div>
<div id="m7" class="Menu">...</div>
<div id="m8" class="Menu">...</div>
<div id="m9" class="Menu">...</div>
I want to group every 4 <div> upon the condition this.props.index % 5 !== 0 to get HTML below:
<div id="m0" class="Menu">...</div>
<div class="MenuRight">
<div id="m1" class="Menu">...</div>
<div id="m2" class="Menu">...</div>
<div id="m3" class="Menu">...</div>
<div id="m4" class="Menu">...</div>
</div>
<div id="m5" class="Menu">...</div>
<div class="MenuRight">
<div id="m6" class="Menu">...</div>
<div id="m7" class="Menu">...</div>
<div id="m8" class="Menu">...</div>
<div id="m9" class="Menu">...</div>
</div>
Any help would be appreciated.
[Edit]
index doesn't matter. It can be the same as it is now or relative to the group. I just described it in the example code to make it more clear.
At the condition this.props.index % 5 === 0, the element <div class="Menu"> would be standalone, else the other elements would be grouped with <div class="MenuRight">.
It would be complex to regroup the tags after they've already been mapped to a flat list of TemplateMenu, as each element is not aware of its position according to their parent's logic.
To solve your problem I would group the elements before mapping them into the final elements, and then rendering them into a single TemplateMenu or the grouped MenuRight.
For example, this is the quickest approach I could think to group them, but of course there are many other algorithms you might prefer:
const groupedIds = menuIds.reduce((groups: any[], id: any, index: number) => {
if (index % 5 === 0) {
groups[Math.floor(index / 5) * 2] = [id];
} else {
const groupIndex = Math.floor(index / 5) * 2 + 1;
if (groups[groupIndex]) {
groups[groupIndex].push(id);
} else {
groups[groupIndex] = [id];
}
}
return groups;
}, []);
This would result in an array of ids like [[0],[1,2,3,4],[5],[6,7...]...]. Then you can use these groups to render them in different ways.
Here is a working example with a problem derived from yours (also on CodeSandbox):
function TemplateMenu({ index, id }: { index: number; id: any }) {
return (
<div id={`m${index}`} className="Menu">
{id}
</div>
);
}
/*export default*/ function App() {
const menuIds = ["single 1", 2, 3, 4, 5, "single 2", "a", "b"];
const groupedIds = menuIds.reduce((groups: any[], id: any, index: number) => {
if (index % 5 === 0) {
groups[Math.floor(index / 5) * 2] = [id];
} else {
const groupIndex = Math.floor(index / 5) * 2 + 1;
if (groups[groupIndex]) {
groups[groupIndex].push(id);
} else {
groups[groupIndex] = [id];
}
}
return groups;
}, []);
return (
<div className="App">
{/*{menuIds.map((id, idx) => {
return <TemplateMenu key={id} index={idx} id={id} />;
})}*/}
{groupedIds.map((group, idx) => {
if (group.length === 1) {
return <TemplateMenu key={group[0]} index={idx} id={group[0]} />;
} else {
return (
<div className="MenuRight">
{group.map((id, idx) => {
return <TemplateMenu key={id} index={idx} id={id} />;
})}
</div>
);
}
})}
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
.Menu {
outline: 1px solid red;
}
.MenuRight {
outline: 1px solid blue;
padding: 4px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
You can do this with a simple loop, which to me is by far the clearest way; see comments:
const {menuIds} = category;
const elements = [];
// Include every 5th element directly, including the 0th one;
// group the (up to) four following it
let index = 0;
while (index < menuIds.length) {
// Use this entry directly, note we increment index after using it
// in the `TemplateMenu`
const {menuId} = menuIds[index];
elements.push(
<TemplateMenu
index={index++}
key={menuId}
menu={this.props.menus[menuId]}
menuLayout={category.menu_layout}
/>
);
// Follow it with up to four in a `<div class="MenuRight">`
const following = menuIds.slice(index, index + 4);
if (following.length) {
// Note we increment `index` as we go
elements.push(
<div className="MenuRight">
{following.map(({menuId}) => (
<TemplateMenu
index={index++}
key={menuId}
menu={this.props.menus[menuId]}
menuLayout={category.menu_layout}
/>
))}
</div>
);
}
}
// ...use {elements}...
Live Example:
const {useState} = React;
const TemplateMenu = ({index, menu, menuLayout}) => <div className="TemplateMenu">{menu}</div>;
class Example extends React.Component {
render() {
const category = {
menuIds: [
{menuId: 0},
{menuId: 1},
{menuId: 2},
{menuId: 3},
{menuId: 4},
{menuId: 5},
{menuId: 6},
{menuId: 7},
{menuId: 8},
{menuId: 9},
],
menu_layout: "example",
};
const {menuIds} = category;
const elements = [];
// Include every 5th element directly, including the 0th one;
// group the (up to) four following it
let index = 0;
while (index < menuIds.length) {
// Use this entry directly, note we increment index after using it
// in the `TemplateMenu`
const {menuId} = menuIds[index];
elements.push(
<TemplateMenu
index={index++}
key={menuId}
menu={this.props.menus[menuId]}
menuLayout={category.menu_layout}
/>
);
// Follow it with up to four in a `<div class="MenuRight">`
const following = menuIds.slice(index, index + 4);
if (following.length) {
// Note we increment `index` as we go
elements.push(
<div className="MenuRight">
{following.map(({menuId}) => (
<TemplateMenu
index={index++}
key={menuId}
menu={this.props.menus[menuId]}
menuLayout={category.menu_layout}
/>
))}
</div>
);
}
}
// ...use {elements}...
return <div>{elements}</div>;
}
};
const menus = [
"Menu 0",
"Menu 1",
"Menu 2",
"Menu 3",
"Menu 4",
"Menu 5",
"Menu 6",
"Menu 7",
"Menu 8",
"Menu 9",
];
ReactDOM.render(
<Example menus={menus} />,
document.getElementById("root")
);
.TemplateMenu {
border: 1px solid green;
margin: 4px;
}
.MenuRight {
margin: 4px;
padding: 4px;
border: 1px solid red;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
You can reduce the categories.menuIds array to a 2D array similar to the mentioned structure. For ex. [[0], [1, 2, 3, 4], [5], [6, 7, 8, 9]...]. Now even index contains MenuItem [0] and odd index contain MenuRight [1, 2, 3, 4]. Now we can conditionally render this using Array.map().
Working Example : Demo Link
First Reduce the categories.menuIds array
const menuIds = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const transformed = menuIds.reduce((acc, curr, idx) => {
if (idx % 5 === 0) {
const i = Math.floor(idx / 5) * 2;
acc[i] = [curr];
} else {
const parentIdx = Math.floor(idx / 5) * 2 + 1;
acc[parentIdx] = acc[parentIdx] || [];
acc[parentIdx] = [...acc[parentIdx], curr];
}
return acc;
}, []);
console.log(transformed);
Render this in React using Array.map()
<div className="App">
{transformed.map((item, idx) => {
return (
<>
{idx % 2 === 0 && (
<div key={idx} className="Menu">
{item}
</div>
)}
{idx % 2 === 1 && (
<div key={idx} className="MenuRight">
{item.map((menuRight, i) => (
<div key={i} className="Menu">
{menuRight}
</div>
))}
</div>
)}
</>
);
})}
</div>

how can i change dom element with component

import {
NotificationIcon,
SummaryIcon,
PublishIcon,
EngageIcon,
ListenIcon,
ReportIcon,
PlusIcon,
MinusIcon,
} from "../../icons/Icons";
import "./Sidebar.scss";
import ReactDOM from "react-dom";
const Sidebar = () => {
// handle accordion menu's open effect
const handleClassName = (arg) => {
const element = document.getElementById(arg);
element.classList.toggle("show");
element.firstElementChild.lastElementChild.remove()
};
const handleBrandsIcon = (arg) => {
const allBrands = document.querySelectorAll(".sidebar__brand");
for (let i = 0; i < allBrands.length; i++) {
allBrands[i].classList.remove("active");
document.getElementById(arg).classList.add("active");
}
};
const contentBox = [
{
id: 0,
icon: <SummaryIcon className="sidebar__icon" />,
label: "SUMMARY",
iconType: "summary",
},
{
id: 1,
icon: <PublishIcon className="sidebar__icon" />,
label: "PUBLISH",
iconType: "publish",
},
{
id: 2,
icon: <EngageIcon className="sidebar__icon" />,
label: "ENGAGE",
iconType: "engage",
},
{
id: 3,
icon: <ListenIcon className="sidebar__icon" />,
label: "LISTEN",
iconType: "listen",
},
{
id: 4,
icon: <ReportIcon className="sidebar__icon" />,
label: "REPORT",
iconType: "report",
},
];
const brands = [
{
img: "./gucci.gif",
id: 10,
},
{
img: "./coca-cola.gif",
id: 11,
},
{
img: "./pepsi.gif",
id: 12,
},
{
img: "./samsung.png",
id: 13,
},
{
img: "./tesla.gif",
id: 14,
},
{
img: "./twitter.png",
id: 15,
},
];
return (
<div className="sidebar">
<h2 className="sidebar__header">
sociality<label>.io</label>
</h2>
<div className="sidebar__wrapper">
<div className="sidebar__brands">
{brands.map((brand) => {
return (
<div
id={brand.id}
className="sidebar__brand"
onClick={() => handleBrandsIcon(brand.id)}
>
<img src={brand.img} className="sidebar__img" alt="/" />
</div>
);
})}
</div>
<div className="sidebar__accordion">
<div className="sidebar__content-box">
<div className="sidebar__row">
<NotificationIcon />
<label className="sidebar__label">NOTIFICATIONS</label>
<label className="sidebar__label sidebar__label--rounded">
28
</label>
</div>
<ul className="sidebar__list">
<li className="sidebar__item">Compase</li>
<li className="sidebar__item">Feed</li>
</ul>
</div>
{contentBox.map((content) => {
return (
<div
id={content.id}
className="sidebar__content-box"
onClick={() => handleClassName(content.id)}
>
<div className="sidebar__row">
{content.icon}
<label className="sidebar__label">{content.label}</label>
<PlusIcon className="sidebar__plus" />
</div>
<ul className="sidebar__list">
<li className="sidebar__item">Compase</li>
<li className="sidebar__item">Feed</li>
</ul>
</div>
);
})}
</div>
</div>
</div>
);
};
export default Sidebar;
Hi guys have a good day.When i click to div element which has .sidebar__row class name i want to change <PlusIcon/> with <MinusIcon/>.I progressed it to the phase of remove <PlusIcon/> component but i couldnt any way to add <MinusIcon/> component instead of <PlusIcon/>.In addition i tried add ReactDOM.render(<MinusIcon className="sidebar__plus" /> , element.firstChild) end of handleClassName function and i could add instead of but this time all children elements of <div className="sidebar__row"> have been deleted.Finally if u see any absurd things in my code can u give me advice to write more clean code.
Add state to hold the current selected brand id and conditionally add the "active" class if the currently mapped brand id matches the state.
Add state to hold a map of toggled content ids, and conditionally render the unordered list and plus/minus icon on the current content's id match.
The contentBox and brands arrays are static so they can be pulled out of the component, defined outside it.
const contentBox = [.....];
const brands = [.....];
const Sidebar = () => {
const [showBrandId, setShowBrandId] = React.useState(null);
const [showContentIds, setShowContentIds] = React.useState({});
// handle accordion menu's open effect
const handleClassName = (contentId) => {
setShowContentIds(ids => ({
...ids,
[contentId]: !ids[contentId], // toggles boolean
}));
};
const handleBrandsIcon = (brandId) => {
setShowBrandId(brandId); // replaces current active brand
};
return (
<div className="sidebar">
<h2 className="sidebar__header">
sociality<label>.io</label>
</h2>
<div className="sidebar__wrapper">
<div className="sidebar__brands">
{brands.map((brand) => {
return (
<div
id={brand.id}
className={"sidebar__brand " + brand.id === showBrandId ? "active" : ""}
onClick={() => handleBrandsIcon(brand.id)}
>
<img src={brand.img} className="sidebar__img" alt="/" />
</div>
);
})}
</div>
<div className="sidebar__accordion">
<div className="sidebar__content-box">
<div className="sidebar__row">
<NotificationIcon />
<label className="sidebar__label">NOTIFICATIONS</label>
<label className="sidebar__label sidebar__label--rounded">
28
</label>
</div>
<ul className="sidebar__list">
<li className="sidebar__item">Compase</li>
<li className="sidebar__item">Feed</li>
</ul>
</div>
{contentBox.map((content) => {
const showContent = showContentIds[content.id];
return (
<div
id={content.id}
className={"sidebar__content-box" + showContent ? "show" : ""}
onClick={() => handleClassName(content.id)}
>
<div className="sidebar__row">
{content.icon}
<label className="sidebar__label">{content.label}</label>
{showContent ? (
<MinusIcon className="sidebar__minus" />
) : (
<PlusIcon className="sidebar__plus" />
)}
</div>
{showContent && (
<ul className="sidebar__list">
<li className="sidebar__item">Compase</li>
<li className="sidebar__item">Feed</li>
</ul>
)}
</div>
);
})}
</div>
</div>
</div>
);
};

Hi ! React issues i need assistance with event handlers

I'm trying to make a components props(sideBarInfo) details show up on the left column of a Page after clicking on a corresponding component(thumbnail) on the right column of the same Page.
Please note that all imports and exports are used in the main project(i removed them here).
I've also imported all components into the main (Page.js). Yet i keep getting a Type error for the onClick.
This is the first component - Thumbnail
class Thumbnail extends React.Component {
render(){
return (
<div className="Work" onClick={(e) => this.props.click(this.props.work)} >
<div className="image-container">
<img src={this.props.work.imageSrc} alt={this.props.work.imageSrc}/>
</div>
<div className="Work-information">
<p> {this.props.work.work}</p>
</div>
</div>
);
} }
This is the ThumbnailList
class ThumbnailList extends React.Component {
constructor(props){
super(props);
this.state= {
works: [
{
id: 0,
work: 'Work 1',
imageSrc: W1,
view: '#',
selected: false
},
{
id: 1,
work: 'Work 2',
imageSrc: W2,
view: '#',
selected: false
},
]
}
}
handleCardClick = (id,card) => {
console.log(id);
let works= [...this.state.works];
works[id].selected = works[id].selected ? false : true ;
works.forEach(work=>{
if(work.id !== id){
work.selected = false;
}
});
this.setState({
works
})
}
makeWorks = (works) => {
return works.map(work => {
return <Thumbnail work={work} click={(e => this.handleCardClick(work.id,e ))} key={work.id} />
})
}
render(){
return(
<div>
<div className="scrolling-wrapper-flexbox">
{this.makeWorks(this.state.works)}
</div>
</div>
);
}
}
This is the sidebarInfo
function SidebarInfo(props) {
return (
<img width="370" height="370" src= {props.imageSrc} />
<p> {props.work} </p>
);}
This is the problematic Page - the boldened keeps giving a Type error(cannot read property 'selected' of undefined.)
class Page extends React.Component {
render() {
return (
<span>
<div className="column left">
<div className="">
**{this.props.work.selected && <SidebarInfo imageSrc={this.props.imageSrc} /> }**
</div>
</div>
<div className="column right" >
<div>
<ThumbnailList />
</div>
</div>
</span>
)
}
}
You may need to add a check in this.props.work.selected like this this.props.work && this.props.work.selected
To ensure that this.props.work is defined before checking on this.props.work.selected
I was able to answer this for anyone interested.
there were some foundational errors in my file arrangement which have been corrected.
After refactoring, i was able to achieve what i wanted using 3 classes/functions in; App.js, Thumbnail.js and SideBarInfo.js
see one working solution with styling on this sandbox: https://codesandbox.io/s/modern-sky-y9d3c
See Solution below;
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
works: [
{
id: 0,
work: "Work 1",
imageSrc:
"https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
},
{
id: 1,
work: "Work 2",
imageSrc:
"https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=701&q=80",
view: "#",
selected: false
}
]
};
this.handleCardClick = this.handleCardClick.bind(this);
this.makeWorks = this.makeWorks.bind(this);
this.showWorks = this.showWorks.bind(this);
}
handleCardClick = (id, Thumbnail) => {
console.log(id);
let works = [...this.state.works];
works[id].selected = works[id].selected ? false : true;
works.forEach((work) => {
if (work.id !== id) {
work.selected = false;
}
});
this.setState({
works
});
};
makeWorks = (works) => {
return works.map((work) => {
return (
<Thumbnail
work={work}
click={(e) => this.handleCardClick(work.id, e)}
key={work.id}
/>
);
});
};
showWorks = (works) => {
let i = 0;
var w = [];
while (i < works.length) {
if (works[i].selected) {
w = works[i];
}
i++;
}
return ( <SidebarInfo imageSrc={w.imageSrc} work={w.work} /> );
};
render() {
return (
<div className="App">
<span>
<div> { this.showWorks(this.state.works)} </div>
<div className="">
<div className="scrolling-wrapper-flexbox">
{this.makeWorks(this.state.works)}
</div>
</div>
</span>
</div>
);
}
}
class Thumbnail extends React.Component {
render() {
return (
<div>
<div className="column left">
{/* this.props.work.selected && <SidebarInfo work={this.props.work.work} imageSrc={this.props.work.imageSrc}/> */}
</div>
<div className="column right">
<div className="Work" onClick={(e) => this.props.click(this.props.work)}>
<div className="image-container">
<img src={this.props.work.imageSrc} alt={this.props.work.imageSrc} />
</div>
<div className="Work-information">
<p> {this.props.work.work}</p>
</div>
</div>
</div>
</div>
);
}
}
export default Thumbnail;
function SidebarInfo(props) {
return (
<div className="one">
<div className="Work">
<h1> NAME </h1>
<div className="image-container">
<img
width="370"
height="370"
src={props.imageSrc}
alt={props.imageSrc}
/>
</div>
<p> {props.work} </p>
<p> {props.view} </p>
</div>
</div>
);
}
export default SidebarInfo;

How to render an array of objects in React?

could you please tell me how to render a list in react js.
I do like this
https://plnkr.co/edit/X9Ov5roJtTSk9YhqYUdp?p=preview
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
hello
</div>
);
}
}
You can do it in two ways:
First:
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>);
return (
<div>
{listItems }
</div>
);
}
Second: Directly write the map function in the return
render() {
const data =[{"name":"test1"},{"name":"test2"}];
return (
<div>
{data.map(function(d, idx){
return (<li key={idx}>{d.name}</li>)
})}
</div>
);
}
https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions
You can pass any JavaScript expression as children, by enclosing it within {}. For example, these expressions are equivalent:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
}
class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [{name: 'bob'}, {name: 'chris'}],
};
}
render() {
return (
<ul>
{this.state.data.map(d => <li key={d.name}>{d.name}</li>)}
</ul>
);
}
}
ReactDOM.render(
<First />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Shubham's answer explains very well. This answer is addition to it as per to avoid some pitfalls and refactoring to a more readable syntax
Pitfall : There is common misconception in rendering array of objects especially if there is an update or delete action performed on data. Use case would be like deleting an item from table row. Sometimes when row which is expected to be deleted, does not get deleted and instead other row gets deleted.
To avoid this, use key prop in root element which is looped over in JSX tree of .map(). Also adding React's Fragment will avoid adding another element in between of ul and li when rendered via calling method.
state = {
userData: [
{ id: '1', name: 'Joe', user_type: 'Developer' },
{ id: '2', name: 'Hill', user_type: 'Designer' }
]
};
deleteUser = id => {
// delete operation to remove item
};
renderItems = () => {
const data = this.state.userData;
const mapRows = data.map((item, index) => (
<Fragment key={item.id}>
<li>
{/* Passing unique value to 'key' prop, eases process for virtual DOM to remove specific element and update HTML tree */}
<span>Name : {item.name}</span>
<span>User Type: {item.user_type}</span>
<button onClick={() => this.deleteUser(item.id)}>
Delete User
</button>
</li>
</Fragment>
));
return mapRows;
};
render() {
return <ul>{this.renderItems()}</ul>;
}
Important : Decision to use which value should we pass to key prop also matters as common way is to use index parameter provided by .map().
TLDR; But there's a drawback to it and avoid it as much as possible and use any unique id from data which is being iterated such as item.id. There's a good article on this - https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
Try this below code in app.js file, easy to understand
function List({}) {
var nameList = [
{ id: "01", firstname: "Rahul", lastname: "Gulati" },
{ id: "02", firstname: "Ronak", lastname: "Gupta" },
{ id: "03", firstname: "Vaishali", lastname: "Kohli" },
{ id: "04", firstname: "Peter", lastname: "Sharma" }
];
const itemList = nameList.map((item) => (
<li>
{item.firstname} {item.lastname}
</li>
));
return (
<div>
<ol style={{ listStyleType: "none" }}>{itemList}</ol>
</div>
);
}
export default function App() {
return (
<div className="App">
<List />
</div>
);
}
import React from 'react';
class RentalHome extends React.Component{
constructor(){
super();
this.state = {
rentals:[{
_id: 1,
title: "Nice Shahghouse Biryani",
city: "Hyderabad",
category: "condo",
image: "http://via.placeholder.com/350x250",
numOfRooms: 4,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 43
},
{
_id: 2,
title: "Modern apartment in center",
city: "Bangalore",
category: "apartment",
image: "http://via.placeholder.com/350x250",
numOfRooms: 1,
shared: false,
description: "Very nice apartment in center of the city.",
dailyPrice: 11
},
{
_id: 3,
title: "Old house in nature",
city: "Patna",
category: "house",
image: "http://via.placeholder.com/350x250",
numOfRooms: 5,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 23
}]
}
}
render(){
const {rentals} = this.state;
return(
<div className="card-list">
<div className="container">
<h1 className="page-title">Your Home All Around the World</h1>
<div className="row">
{
rentals.map((rental)=>{
return(
<div key={rental._id} className="col-md-3">
<div className="card bwm-card">
<img
className="card-img-top"
src={rental.image}
alt={rental.title} />
<div className="card-body">
<h6 className="card-subtitle mb-0 text-muted">
{rental.shared} {rental.category} {rental.city}
</h6>
<h5 className="card-title big-font">
{rental.title}
</h5>
<p className="card-text">
${rental.dailyPrice} per Night ยท Free Cancelation
</p>
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
)
}
}
export default RentalHome;
Try this:
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
{listItems}
</div>
);
}
}

Categories

Resources