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

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

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

State not updating with useState set method

I'm trying to learn hooks and try to update the state using onMouseEnter and Leave events, but the state in isFlip.flipStat doesn't change, it used for flag to flipping the card using ReactCardFlip components. The only issues here is my state doesn't change when handleMouse function trigger, maybe anyone can help. Thanks in advance.
Here's my code :
function OurServices() {
const [isFlip, setFlip] = useState([])
const listServices = [
{
"title": "title",
"img": "img.jpg",
"desc": "lorem ipsum"
}
]
function handleMouse(key) {
let newArr = [...isFlip]
newArr[key].flipStat = !newArr[key].flipStat
setFlip(newArr)
}
useEffect(() => {
listServices.map((x) => (
x.flipStat = false
))
setFlip(listServices)
})
return (
{isFlip.map((x, key) => (
<div key={key} onMouseEnter={() => handleMouse(key)} onMouseLeave={() => handleMouse(key)}>
<div className={styles.card} >
<div className={styles.card_body+" p-xl-0 p-lg-0 p-md-1 p-sm-1 p-0"}>
<ReactCardFlip isFlipped={x.flipStat} flipDirection="horizontal">
<div className="row">
<div className={"col-xl-12 text-center "+styles.services_ic}>
<img className="img-fluid" src={x.img} width="72" height="72" alt="data-science" />
</div>
<div className={"col-xl-11 mx-auto text-center mt-4 "+styles.services_desc}>{x.title}</div>
</div>
<div className="row">
<div className={"col-xl-12 text-center "+styles.services_ic}>
{parse(x.desc)}
</div>
</div>
</ReactCardFlip>
</div>
</div>
</div>
))}
)```
The first problem is in your useEffect,
useEffect(() => {
listServices.map((x) => (
x.flipStat = false
))
setFlip(listServices)
})
you are setting listServices as the isFlip array. But Array.map() method doesn't update the source array. You need to write like this,
useEffect(() => {
const updatedArr = listServices.map((x) => (
x.flipStat = false
return x;
))
setFlip(updatedArr)
})
And can you log newArr after this line let newArr = [...isFlip] and see if that array has all the items? It should help you debug the issue.
Update:
Try creating new array while setting the state,
function handleMouse(key) {
let newArr = [...isFlip]
newArr[key].flipStat = !isFlip[key].flipStat
setFlip([...newArr])
}
The main problem is apparently from my code to adding flipsStat key to the listServices variable, to solving this I change the mapping way to this :
listServices.map((x) => ({
...x, flipStat: false
}))
Thanks for #sabbir.alam to reminds me for this.

How can I loop over a JSON object in React

I'm trying to retrieve information from the following JSON object data.json:
{
"status": "ok",
"feed": {
"title": "NOS Nieuws",
},
"items": [
{
"title": "Test Title",
"description": "Test description",
"enclosure": {
"link": "https://examplelink.com/1008x567.jpg",
"type": "image/jpeg"
},
"categories": []
},
{
"title": "Test Title 2",
"description": "Test 2",
"enclosure": {
"link": "link": "https://examplelink.com/1008x567.jpg",
"type": "image/jpeg"
},
"categories": []
}
]
}
So I want to loop over this JSON object to display all the available items and its corresponding title, description and enclosure-link.
I know i can access them separately as:
const items = data.items;
const title = items.title;
const url = items.enclosure.link;
Usually I would do a for-loop and loop through data.items[i]. However, since this is a react and an object instead of an array it works differently.
My current code:
class Feed extends Component {
render() {
const items = data.items[0];
const title = items.title;
const url = items.enclosure.link;
const description = items.description;
const feed = [
{
url: url,
title: title,
description: description
}
];
return (
<div className="feed">
<h1>Newsfeed</h1>
<div className="columns is-multiline">
{feed.map(article => (
<div className="column is-one-third">
<NewsCard
article={article}
title={items.title}
description={items.description}
/>
</div>
))}
</div>
</div>
);
}
}
Right now its only displaying the first entry of the object (because it has const items = data.items[0]) How can I loop over data.json and display its content in the NewsCard component? I know that each child should have a unique 'key' prop but thats where I'm stuck.
I want to loop over this JSON object to display all the available
items and its corresponding title, description and enclosure-link
Then instead of doing this:
const items = data.items[0];
Try this:
const items = data.items;
Then, you can use the map function, like this:
items.map(item => (
<div className="column is-one-third">
<NewsCard
article={item.enclosure.link}
title={item.title}
description={item.description}
/>
</div>
));
You could do something like this.
class Feed extends Component {
render() {
let newsCards = data.items.map(item => {
<div className="column is-one-third">
<NewsCard
article={item}
title={item.title}
description={item.description}
/>
</div>
});
return (
<div className="feed">
<h1>Newsfeed</h1>
<div className="columns is-multiline">
{newsCards}
</div>
</div>
);
}
}
const feed = data.items
{feed.map(item => (
<div className="column is-one-third">
<NewsCard
article={item.enclosure.link}
title={item.title}
description={item.description}
/>
</div>
))}
try this way

React: Better way of mapping this data

So this is a continuation of previous questions. I just started using react and I've managed to fetch a xml file, convert it to json and then loop through the data. But I think there should be a better way to go through what I've done as I'm using a function I found on another SO answer and then used a map() within it.
Anyways here's the breakdown of my code.
Fetching the xml and converting to json:
componentDidMount() {
axios.get('https://gist.githubusercontent.com/eMatsiyana/e315b60a2930bb79e869b37a6ddf8ef1/raw/10c057b39a4dccbe39d3151be78c686dcd1101aa/guestlist.xml')
.then(res => {
const xml = XMLMapping.load(res.data);
var guests = XMLMapping.tojson(xml);
this.setState({guests: guests});
});
}
The results of the json in console:
Object{
dataset{
record{
0{
company{
$t: "Skippad"
}
first_name{
$t: "Keith"
}
last_name{
$t: "Cook"
}
}
1{
company{
$t: "Skippad"
}
first_name{
$t: "Keith"
}
last_name{
$t: "Cook"
}
}
}
}
}
I'm using this function to map the object and then using a map() within it:
function mapObject(object, callback) {
return Object.keys(object).map(function (key) {
return callback(key, object[key]);
});
}
This is what the final mapping of the data looks like:
{mapObject(this.state.guests, (key, value) => {
return <div key={key}>
{value.record
.filter(
(item,index) => {
return (
item.first_name.$t.toLowerCase().includes(this.state.search.toLowerCase())
//item.last_name.$t.toLowerCase().includes(this.state.search.toLowerCase())
//item.company.$t.toLowerCase().includes(this.state.search.toLowerCase())
)
}
)
.map((item,index) => {
return <div className="columns is-mobile" key={index}>
<div className="column" key={index}>{item.first_name.$t} {item.last_name.$t} <span class="is-hidden-tablet"><br />{item.company.$t}</span></div>
<div className="column is-hidden-mobile" >{item.company.$t}</div>
<div className="column is-hidden-mobile">
<EmailFormdisplay guestid={index} />
</div>
<div className="column is-hidden-mobile">
<PhoneFormdisplay guestid={index} />
</div>
<div className="column is-hidden-tablet is-one-third-mobile">
<Dropdown>
<DropdownTrigger></DropdownTrigger>
<DropdownContent>
<div className="columns">
<div className="column">
<EmailFormdisplay guestid={index} />
</div>
<div className="column">
<PhoneFormdisplay guestid={index} />
</div>
</div>
</DropdownContent>
</Dropdown>
</div>
</div>;
})}
</div>
})}
Is there a better way of doing this without using mapObject() and a map() within it?
Any kind of feedback or advice would be greatly appreciated!

React - how to map nested object values?

I am just trying to map nested values inside of a state object. The data structure looks like so:
I want to map each milestone name and then all tasks inside of that milestone. Right now I am trying to do so with nested map functions but I am not sure if I can do this.
The render method looks like so:
render() {
return(
<div>
{Object.keys(this.state.dataGoal).map( key => {
return <div key={key}>>
<header className="header">
<h1>{this.state.dataGoal[key].name}</h1>
</header>
<Wave />
<main className="content">
<p>{this.state.dataGoal[key].description}</p>
{Object.keys(this.state.dataGoal[key].milestones).map( (milestone, innerIndex) => {
return <div key={milestone}>
{milestone}
<p>Index: {innerIndex}</p>
</div>
})}
</main>
</div>
})}
</div>
);
}
I think that I could somehow achieve that result by passing the inner index to this line of code: {Object.keys(this.state.dataGoal[key].milestones) so it would look like: {Object.keys(this.state.dataGoal[key].milestones[innerIndex]).
But I am not sure how to pass the innerIndex up. I have also tried to get the milestone name by {milestone.name} but that doesn't work either. I guess that's because I have to specify the key.
Does anybody have an idea? Or should I map the whole object in a totally different way?
Glad for any help,
Jakub
You can use nested maps to map over the milestones and then the tasks array:
render() {
return (
<div>
{Object.keys(this.state.dataGoal.milestones).map((milestone) => {
return (
<div>
{this.state.dataGoal.milestones[milestone].tasks.map((task, idx) => {
return (
//whatever you wish to do with the task item
)
})}
</div>
)
})}
</div>
)
}
What you want is flatMap. flatMap takes an array and a function that will be applied to each element in the array, which you can use to (for example) access properties inside each object in the array. It then returns a new array with the returned values from its lambda:
function flatMap(arr, lambda) {
return Array.prototype.concat.apply([], arr.map(lambda))
}
In our case, we don't have an array, we have an object so we can't use flatMap directly. We can convert the object to an array of its properties' values with Object.values and then make a function that accesses the object with the passed key:
function tasksFromDataGoal(key) {
return flatMap(Object.values(dataGoal[key].milestones), milestone => milestone.tasks)
}
Working example:
function flatMap(arr, lambda) {
return Array.prototype.concat.apply([], arr.map(lambda))
}
function tasksFromDataGoal(key) {
return flatMap(Object.values(dataGoal[key].milestones), milestone => milestone.tasks)
}
const dataGoal = { 123: { milestones: { milestone1: { tasks: ['a', 'b'] }, milestone2: { tasks: ['c', 'd'] } } } }
alert(tasksFromDataGoal('123'))
Author of this implementation of flatMap: https://gist.github.com/samgiles/762ee337dff48623e729
Managed to refactor the render method:
render() {
return(
<div>
{Object.keys(this.state.dataGoal).map( (key, index) => {
const newDataGoal = this.state.dataGoal[key].milestones;
return <div key={key}>
<header className="header">
<h1>{this.state.dataGoal[key].name}</h1>
</header>
<Wave />
<main className="content">
<p>{this.state.dataGoal[key].description}</p><br /><br />
{Object.keys(this.state.dataGoal[key].milestones).map( (milestoneKey) => {
const milestonesData = this.state.dataGoal[key].milestones[milestoneKey];
return <div className="milestone-wrap" key={milestoneKey}>
<label className="milestone-label">{milestonesData.name}</label>
{Object.keys(milestonesData.tasks).map( (taskKey) => {
return <div className="task clearfix" key={taskKey}>
<input
className="checkbox-rounded"
name="task"
type="checkbox"
checked={milestonesData.tasks[taskKey].done}
onChange={(e) => this.handleInputChange(e, key, taskKey)} />
<div className="task-content">
<p className="task-name">{milestonesData.tasks[taskKey].name}</p>
<p className="task-date">{milestonesData.tasks[taskKey].finishDate}</p>
</div>
</div>
})}
</div>
})}
</main>
</div>
})}
</div>
);
}

Categories

Resources