How to create loop inside React return? - javascript

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>
);
};

Related

How to get the "x" element in React JS while using the map object

I have an array with objects I am using map to render the elements on the page, The problem is that I want to get the last object from the array (in my case it is 'documents') and set a class for it to style it, you can also see my code in codesandbox
export default function Nav() {
const [navItems] = useState([
{
id: 1,
name: "Home",
link: "/dashboard"
},
{
id: 2,
name: "Investments",
link: "/investments"
},
{
id: 3,
name: "Organize",
link: "/organize"
},
{
id: 4,
name: "Documents",
link: "/documents"
}
]);
return (
<div className="App">
{navItems.map((i) => {
return (
<div key={i.id}>
<p>{i.name}</p>
</div>
);
})}
</div>
);
}
Check the index of the item while mapping through it. And check if the index is equal to the navItems.length - 1. Check this-
<div className="App">
{navItems.map((item, index) => {
return (
<div
key={item.id}
className={index === navItems.length - 1 ? 'your-desired-class': ''}>
<p>{item.name}</p>
</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>
);
};

Use ternary operator to show specific items from state

I'm unable to show conditional output with the ternary operator. I want to pass a value to a function and show only related info from the state. My code:
import React, {useState} from 'react';
function Tasks({taskId, index}){
{task.parentId == taskId : } //Unable to code this.
return( //show only tasks where parentId == taskId
<div>
<div> {task.title} </div>
<div> {task.body} </div>
</div>
)
}
function App(){
const[tasks, setTasks] = useState([
{
taskId: 1,
title: 'Task1',
body: 'This is the body of the task1',
isComplete: false,
parentId: 0
},
{
taskId: 2,
title: 'Task2',
body: 'This is the body of the task2',
isComplete: false,
parentId: 1
},
{
taskId: 3,
title: 'Task3',
body: 'This is the body of the task3',
isComplete: false,
parentId: 1
},
{
taskId: 4,
title: 'Task4',
body: 'This is the body of the task4',
isComplete: false,
parentId: 3
}
])
return(
<div style={{marginLeft: 20}}>
<h1>ToDo</h1>
{tasks.map((task, index)=>
<Tasks
taskId=1
/>
)}
</div>
)
}
export default App;
So, I want to only show the tasks that have the parentId as 1. How should I go about this?
If you're trying to render only those tasks with the specified id, you may not have to use the ternary operator.
function renderTasks(id) {
return tasks
.filter(({ taskId }) => taskId == id)
.map(({ title, body }) => (
<div>
<div> {title} </div>
<div> {body} </div>
</div>
));
}
For the least modification to the code, you can return an empty fragment or null:
function Tasks({ task }) {
return task.parentId == task.taskId
? (
<div>
<div> {task.title} </div>
<div> {task.body} </div>
</div>
)
: null;
}
(make sure to use parentId, not pasrentId, and task.taskId, not taskId - you aren't passing task as a prop currently, so change the code to do so: <Tasks task={task} />)
But I think it'd make more sense to use .filter in the caller:
return (
<div style={{ marginLeft: 20 }}>
<h1>ToDo</h1>
{tasks
.filter(task => task.parentId === task.taskId)
.map(task => <Task task={task} />)
}
</div>
)
(since Tasks renders a single task, consider calling it Task instead of Tasks)

iterating through an array of objects and displaying the items [REACT JS]

I'm trying to iterate through an array of objects, displaying the results inside divs but something is not working as intended. When I console log it seems to retrieve the data and show it.
const example =
{
"example": [
{
"test": "test",
"img": "img.png",
"song": "song title"
},
{
"test": "test2",
"img": "img.png2",
"song": "song title2"
}
]
}
const renderData= () => {
example.example.forEach(function (arrayItem) {
const test= arrayItem.test
const img= arrayItem.img
const song= arrayItem.song
return (
<div className="test">
<div className="test">
<div className="test">
<img
src={img}
alt="sunil"
/>
</div>
<div className="test">
{test}
<span className="test">
</span>
<p>{song}</p>
</div>
</div>
</div>
);
});
};
return (
<div
{renderData()}
</div>
);
}
nothing really shows up, but when i do:
example.example.forEach(function (arrayItem) {
var x = arrayItem.test+ arrayItem.img+ arrayItem.song;
console.log(x);
});
it works and consoles the right info.
Can anyone spot the mistake or help out?
Please ignore the naming convention.
You need return array of JSX.Element from renderData. In your case you return undefined. Return a new array of JSX.Element with map instead forEach, which returns nothing.
const renderData = () => {
return example.example.map((arrayItem, i) => {
const test = arrayItem.test;
const img = arrayItem.img;
const song = arrayItem.song;
return (
<div key={i} className="test">
<div className="test">
<div className="test">
<img src={img} alt="sunil" />
</div>
<div className="test">
{test}
<span className="test"></span>
<p>{song}</p>
</div>
</div>
</div>
);
});
};

State is undefined

I'am trying to fetch data from an API, then set it on my State and display that state in a table. The issue is that the render method is called first and causes my state to be undefined which causes this issue:
The console.log()
https://i.gyazo.com/642f8d6fe3481d2db9763091618e19de.png
state = {
loading: true,
data: [],
customColumns: [],
}
componentDidMount = () => {
axios.get('http://localhost:8080/lagbevakning/revision/subscriptions?id=' + (this.props.match.params.id)).then(response => {
this.setState({
data: response.data,
loading: false
})
})
axios.get('http://localhost:8080/lagbevakning/company?id=' + sessionStorage.getItem("id")).then(response2 => {
this.setState({
customColumns: response2.data
})
})
}
displayCustomColumn = (columnInput) => {
if(columnInput === null) {
return
} else {
return <Table.HeaderCell>{columnInput}</Table.HeaderCell>
}
}
displayList = () => {
return (
<div>
<Table celled>
<Table.Header>
<Table.Row>
{this.displayCustomColumn(this.state.customColumns.customHeaderName1)}
{this.displayCustomColumn(this.state.customColumns.customHeaderName2)}
</Table.Row>
</Table.Header>
{this.state.data.map((item, i) => (
<Table.Body key={i}>
<Table.Row>
<Table.Cell>{item}</Table.Cell>
<Table.Cell>{item}</Table.Cell>
</Table.Row>
</Table.Body>
))}
</Table>
</div>
)}
render() {
return (
<div>
{this.state.loading
? <div><h1>LOADING...</h1></div>
:
<h2> Company Name: {this.state.customColumns.companyName} <br/>
Revision Name: {this.state.data.name} <br/>
Revision ID: {this.state.data.id} </h2>
}
{this.displayList()}
</div>
)
}
}
Any suggestions on how to solve this issue is much appreciated, thank you.
render() {
return (
<div>
{this.state.loading
? <div><h1>LOADING...</h1></div>
:
<h2> Company Name: {this.state.customColumns.companyName} <br/>
Revision Name: {this.state.data.name} <br/>
Revision ID: {this.state.data.id} </h2>
}
{this.displayList()}
</div>
)
}
I think you are expecting data to be array so you can't access name and id from data state. Check structure of your response and set it accordingly.
Can you try adding the following :
render() {
return (
<div>
{this.state.loading
? <div><h1>LOADING...</h1></div>
:
<h2> Company Name: {this.state.customColumns.companyName} <br/>
Revision Name: {this.state.data.name} <br/>
Revision ID: {this.state.data.id} </h2>
}
{this.state.data.length > 0 && this.displayList()}
</div>
)
}
You can probably try this.
render() {
if (this.state.loading) return <div><h1>LOADING...</h1></div>;
return (
<div>
{this.state.data && this.state.data.length &&
<div>
<h2> Company Name: {this.state.customColumns.companyName} <br />
Revision Name: {this.state.data.name} <br />
Revision ID: {this.state.data.id} </h2>
}
{this.displayList()}
</div>
</div>
)
}
}
You can return immediately if loading is true.
Below that you can check for data which is array of objects.

Categories

Resources