I am deveoping a Kanban Board. I use ReactJS to call the backend for stages and tasks that are open in each stage. It is a very simple JSON that I get from the backend.
JSON
[
{
"open_tasks": [
{
"task_id": 37,
"task_title": "Develop frontend"
},
{
"task_id": 38,
"task_title": "Create app"
}
],
"stage_id": 6,
"stage_title": "Tasks"
},
{
"open_tasks": [],
"stage_id": 15,
"stage_title": "Blocked"
},
{
"open_tasks": [],
"stage_id": 18,
"stage_title": "Finished"
}
]
Now I want to use ReactJS to print the nested JSON, however I cannot use map inside a map.
import { useEffect, useState } from "react";
export function IndexKanbanBoard() {
const [stagesWithOpenTasks, setStagesWithOpenTasks] = useState(() => []);
// Load stages
const loadStagesWithOpenTasksForBoard = async (e) => {
let result = await fetch("https://localhost:5002/api/kanban_boards/get_stages_with_open_tasks_for_board", {
method: "GET",
headers: {
'Authorization': 'Bearer ' + 'bla bla'
}
});
let resultJson = await result.json();
if (result.status === 200) {
setStagesWithOpenTasks(resultJson.map(fetch_object => {
return fetch_object
}))
}
};
// On load
useEffect(() => {
loadStagesWithOpenTasksForBoard()
}, []);
return (
<div>
{stagesWithOpenTasks.map((item, index) => (
<div key={index}>
<h2>{item.stage_title}</h2>
<p>I WANT TO SHOW open_tasks HERE</p>
</div>
))}
</div>
);
}
export default IndexKanbanBoard;
How can i loop trough nested JSON in ReactJS?
Assigning the next array items to a variable will help please have a look
return (
<div>
{data.map((item, index) => {
const openTasks = item["open_tasks"];
return (
<div key={index}>
<h2>{item.stage_title}</h2>
{openTasks.map((item) => (
<p>{item.task_title}</p>
))}
<p></p>
</div>
);
})}
</div>
);
Related
I'm trying to get specific values from an array object returned by my node.js api
Here's the array of object returned by my node.js api
[
{
"name": "device1",
"serial": "WMD105222022",
"status": "online"
},
{
"name": "device2q",
"serial": "sdfsdf",
"status": "online"
},
{
"name": "ducs",
"serial": "WMD105222022",
"status": "online"
}
]
Here's my react.js code
import React, {useState, useEffect} from "react";
import './Module.css';
import {SDH} from '../../components';
import {temp, water, humidity, nutrient} from '../../assets';
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
import Form from 'react-bootstrap/Form';
import {Link} from 'react-router-dom';
import Axios from "axios";
const Module = () => {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const email = sessionStorage.getItem("email");
const [device, setDevice] = useState({});
Axios.defaults.withCredentials = true;
useEffect(() => {
Axios.get("http://localhost:3020/getdevice", {
params: {
email: email
}
})
.then((response) => {
setDevice(response.data);
})
// .then((response) => {},
// (err) => {
// alert("No Data To Show");
// }
// )
.catch((err) => {
return false;
});
},[]);
const DisplayData = () => {
return (
<div>
<td>{device.name}</td>
<td>{device.serial}</td>
<td>{device.status}</td>
</div>
);
};
return (
<div className="MainBodyM">
<SDH/>
<h3 className="deviceStatus"></h3>
{/* <Button onClick={getDevices} variant="primary" type="submit">Refresh List</Button> */}
<div className="tempHeader">
<table>
<tr>
<td>Name</td>
<td>Serial Number</td>
<td>Status</td>
</tr>
<tr>
{DisplayData}
</tr>
</table>
</div>
<Link to="/registerdevice">
<Button>Add Control Module</Button>
</Link>
</div>
);
};
export default Module;
I needed to get the name, serial, and status to be displayed in a table. up until now i'm still getting nowhere, please help, i'm only using {JSON.stringify(device, null, 3)} to display the returned array of object that's why i know i'm getting an array of object. I'm open to suggestions and correction. Thank you.
I need the output to be like this, regardless how many devices/data i add in array of object.
Device Serial Status
Device1 121 online
device2 234135 offline
balcony ash3 online
bathroom dsgfkahaskj23 online
so on... tj2l5 offline
You must send an array from the backend. You must send a JSON
In express
app.get("/test", (req, res) => {
res.json({
array: [
{
name: "device1",
serial: "WMD105222022",
status: "online",
},
{
name: "device2q",
serial: "sdfsdf",
status: "online",
},
{
name: "ducs",
serial: "WMD105222022",
status: "online",
},
],
});
});
Note that I send a JSON, not an array
In React:
const [data, setData] = useState([]);
useEffect(() => {
var config = {
method: "get",
url: "http://localhost:3000/test",
headers: {},
};
axios(config)
.then(function (response) {
const data = JSON.stringify(response.data);
const array = JSON.parse(data).array;
setData(array);
})
.catch(function (error) {
console.log(error);
});
}, []);
Note that I convert the JSON to an object to be able to iterate it
the return on the component
<table>
{data &&
data.map((row, key) => {
return (
<tr key={key} style={{ color: "red" }}>
<td>{row.name}</td>
<td>{row.serial}</td>
<td>{row.status}</td>
</tr>
);
})}
</table>
You can extract the columns name, ie. "Device", "Serial", "Status", into an array, and iterate over them using map function:
const [data, setDate] = useState();
const columns = ["Device", "Serial", "Status"]; // hard code the columns
const lookUpDataKey = {
Device: "name",
Serial: "serial",
Status: "status"
};
useEffect(() => {
setDate(dataFromApi); // mimic getting data from api
}, []);
if (!data) return <div>loading</div>;
return (
<div className="App">
<div style={{ display: "flex" }}>
{columns.map((column, columnIndex) => (
<div key={columnIndex}>
{/* Column name */}
<div>{columns[columnIndex]}</div>
{/* Column data */}
{data.map((item, dataIndex) => (
<div key={dataIndex}>
<div>{item[lookUpDataKey[column]]}</div>
</div>
))}
</div>
))}
</div>
</div>
);
Notice we use a lookUpDataKey object for matching column's name to the corresponding object key.
Try it out in updated sandbox.
I am using ReactJs with Laravel as an API. I Want to display some data but nothing worked for me.
This is the result of the API:
{
"user_id": 2,
"id": 1,
"chat": [
{
"sender_id": 3,
"message": "Hi"
},
{
"sender_id": 4,
"message": "Hello"
}
]
}
When I try to display user_id, it displayed it but the other part, the chat, didn't show up.
This is how I consume the API:
const [chatsData, setChats] = useState([]);
// ** Renders Chat
useEffect(() => {
getChats()
}, []);
const getChats = async () => {
const response = await axios.get(`${API_ENDPOINT}/api/listChats`);
setChats(response.data);
}
<ul className='chat-users-list chat-list media-list'>
{chatsData.map((item) => {
return (
<>
<Avatar img={item?.senders?.user_image} imgHeight='42' imgWidth='42' />
<li><h5>{item.chat?.message}</h5></li>
</>
)
})}
</ul>
I will be very thankful if anyone could help me.
You just have to loop on the chat field like:
import React from 'react';
export default function App() {
const response = {
user_id: 2,
id: 1,
chat: [
{
sender_id: 3,
message: 'Hi',
},
{
sender_id: 4,
message: 'Hello',
},
],
};
return (
<div>
<ul className="chat-users-list chat-list media-list">
{response.chat?.map((item) => {
return (
<>
<li>
<h5>
{item.sender_id} : {item?.message}
</h5>
</li>
</>
);
})}
</ul>
</div>
);
}
Code example here
I'm running into a problem that I've been working on for days and unfortunately I can't figure it out by myself. I'm trying to create a View which shows some information from an API. But every time I map this item, I want to do another API call which checks the live price of that product.
So I have for example some JSON data what I get from an API.
{
"id": 1,
"name": "test product",
"productid": "73827duf"
},
{
"id": 2,
"name": "test product2",
"productid": "734437dde"
}
So I show this data with the following code inside my application:
{item.products.map((products) => {
return (
<View
key={products.id}
>
<Text
style={{
fontSize: FONTS.body3,
paddingLeft: 10,
}}
>
{products.name}
{getProductPriceJumbo(
products.productid
)}
</Text>
</View>
);
})}
So I want to run every time a function which fetches data from another API. I'm sending the productID because that's the only information I need to call this API. You can see this function down below:
function getProductPriceJumbo(id) {
fetch("https://---/test.php?id=" + id + "/", {
method: "GET",
})
.then((response) => response.json())
.then((data) => {
return data[0].price;
});
}
So this fetch returns a big list with information about the product from a third party API. I only want to return the price, that's the reason why I only return the price value and I want to print this out on the view above. I can't really figure out how to do this. I get undefined from the function every time I run it. Hope someone can help me with this.
Create a new Price Component to display the price
function Price({ id }) {
const [price, setPrice] = useState(0);
useEffect(() => {
function getProductPriceJumbo(id) {
fetch("https://---/test.php?id=" + id + "/", {
method: "GET"
})
.then((response) => response.json())
.then((data) => {
setPrice(data[0].price);
});
}
getProductPriceJumbo(id);
},[]);
return <Text>{price}</Text>;
}
And your .map will become
{
item.products.map((products) => {
return (
<View key={products.id}>
<Text
style={{
fontSize: FONTS.body3,
paddingLeft: 10
}}
>
{products.name}
<Price id={products.productid} />
</Text>
</View>
);
});
}
The reason you are getting undefined is because the window is rendering before the function finishes running. You will have define an asynchronous function before you return your view.
const [data, setData] = useState([])
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () =>{
setLoading(true);
try {
const {data: response} = await axios.get('API URL');
setData(response);
} catch (error) {
console.error(error.message);
}
setLoading(false);
}
fetchData();
}, []);
Then you can use data[0].price;
You'll probably want to make your individual product into its own component that handles the fetching, and setting the price to a state value that's local to that product view. Here's a full example of how you could do that:
import { useState, useEffect } from "react";
const Product = ({ product }) => {
const [price, setPrice] = useState("Price loading...");
useEffect(() => {
fetch("https://---/test.php?id=" + product.productid + "/", {
method: "GET"
})
.then((response) => response.json())
.then((data) => {
setPrice(data[0].price);
});
}, [product]);
return (
<View>
<Text
style={{
fontSize: FONTS.body3,
paddingLeft: 10
}}
>
{product.name}
{price}
</Text>
</View>
);
};
const App = () => {
const item = {
products: [
{
id: 1,
name: "test product",
productid: "73827duf"
},
{
id: 2,
name: "test product2",
productid: "734437dde"
}
]
};
return (
<div>
{item.products.map((product) => (
<Product key={product.id} product={product} />
))}
</div>
);
};
Alternatively, you could use Promise.all to get all of the price values before mapping your products:
import { useState, useEffect } from "react";
const App = () => {
const [item] = useState({
products: [
{
id: 1,
name: "test product",
productid: "73827duf"
},
{
id: 2,
name: "test product2",
productid: "734437dde"
}
]
});
const [products, setProducts] = useState([]);
useEffect(() => {
Promise.all(
item.products.map(async (product) => {
const response = await fetch(
`https://---/test.php?id=${product.productid}/`
);
const data = await response.json();
return {
...product,
price: data[0].price
};
})
).then((products) => setProducts(products));
}, [item]);
return (
<div>
{products.map((product) => {
return (
<View key={product.id}>
<Text
style={{
fontSize: FONTS.body3,
paddingLeft: 10
}}
>
{product.name}
{product.price}
</Text>
</View>
);
})}
</div>
);
};
My data is not shown when the app launches. It only shows when I tried to inspect the page.
I am reading JSON data that make take some time to be available. So, I added a async/await.
How do I fix my code so it displays on load?
Here is a snippet of my code:
const WeatherWidget = ({ id, editMode }) => {
const [roles, setRoles] = useState();
const getGoalData = async () => {
return (
[
{
"username": "user1",
"goal": "$5,000,200"
},
{
"username": "user2",
"goal": "$5,000,200"
},
{
"username": "user3",
"goal": "$4,000,199"
},
]
);
}
useEffect(() => {
const setDataRole = async () => {
var json = await getGoalData();
setRoles(json)
}
setDataRole();
}, [])
return (
<Container>
<div>
ticker from widget config
</div>
<StyledUl>
<Ticker>
{({ index }) => (
<>
{roles && roles.map(({ username, goal }, i) => (
<>
{i === 0 ? null : ','}
<StyledSpanName>
<span className="name">{username}</span>
</StyledSpanName>
<StyledSpanGoal> <span className="goal">{goal}</span></StyledSpanGoal>
</>
))
}
</>
)}
</Ticker>
</StyledUl>
</Container>
);
};
You don't need to load anything. The data is right there in the code. Just put it in roles right from the start.
In fact, you don't even need to use useState, since you never mutate the roles state. It could (and probably should) be a constant.
const WeatherWidget = ({ id, editMode }) => {
const [roles, setRoles] = useState(
[
{
"username": "user1",
"goal": "$5,000,200"
},
{
"username": "user2",
"goal": "$5,000,200"
},
{
"username": "user3",
"goal": "$4,000,199"
},
]
);
return (
<Container>
<div>
ticker from widget config
</div>
<StyledUl>
<Ticker>
{({ index }) => (
<>
{roles && roles.map(({ username, goal }, i) => (
<>
{i === 0 ? null : ','}
<StyledSpanName>
<span className="name">{username}</span>
</StyledSpanName>
<StyledSpanGoal> <span className="goal">{goal}</span></StyledSpanGoal>
</>
))
}
</>
)}
</Ticker>
</StyledUl>
</Container>
);
};
Seems like you forgot async:
useEffect(() => {
const setDataRole = async () => { // here
var res = await getGoalData()
var data = await res.json()
setRoles(data)
}
setDataRole();
}, [])
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);