Map over an array in React - reactjs

I am building an app that displays video games and various info about them, pulling data from an API. I am trying to display all of the platforms that the game is playable on, PlayStation, Xbox, etc. The JSON has an array of platforms for each game that each contain a platform object with a name (that I am trying to display). Maps really confuse me I would really appreciate someone's help with this. I will include a snippet of the JSON.
"count": 1326,
"next": "https://api.rawg.io/api/games?key=8d1a421af80b4f9b8650de12d9943010&page=2&search=destiny",
"previous": null,
"results": [
{
"slug": "destiny",
"name": "Destiny",
"playtime": 24,
"platforms": [
{
"platform": {
"id": 1,
"name": "Xbox One",
"slug": "xbox-one"
}
},
{
"platform": {
"id": 18,
"name": "PlayStation 4",
"slug": "playstation4"
}
},
{
"platform": {
"id": 14,
"name": "Xbox 360",
"slug": "xbox360"
}
},
{
"platform": {
"id": 16,
"name": "PlayStation 3",
"slug": "playstation3"
}
}
],
const GameCard = ({
game: {
name,
background_image,
metacritic,
released,
platforms,
platform,
esrb_rating,
},
}) => {
return (
<div className="bg-gray-600/30 m-5 p-0 rounded-xl shadow-xl shadow-gray-700 border-solid border-2 border-gray-700 max-w-[640px] hover:scale-105 ease-in duration-300">
<img
className="rounded-t-xl h-[360px] w-[640px] border-b-2 border-gray-600"
alt={name}
src={
background_image
? background_image
: "https://via.placeholder.com/640x360"
}
/>
<h1 className="text-center text-4xl text-gray-900 tracking-wide font-bold mt-2 font-mono">
{name}
</h1>
<div className="text-gray-800 text-center font-mono py-2">
{platforms ? platforms.map(() => <span></span>) : null}

Per W3Schools:
map() creates a new array from calling a function for every array
element.
map() calls a function once for each element in an array.
map() does not execute the function for empty elements.
map() does not change the original array.
This creates an array of names from an array of platform objects, such as results.platforms in the json snippet you showed.
platforms.map(platform => <span>{platform.platform.name}</span>)

If you map over the platform after taking that part to the variable called platforms in your code then you can map over it like I shown below:
<div className="text-gray-800 text-center font-mono py-2">
{platforms ? platforms.map((item) => <span key={item.platform.id}>
{item.platform.name}
</span>) : null }
</div>
Don't forget to insert the key inside the span tag. Which will act as a unique identifier for each span tag.
reference: Lists and Keys

Related

React images not showing in Github (tried previous solutions already)

Notes:
Project previously showed images before uploading it to Gihub.
I have a JSON file of 84 product images so I would like to not use the import export method for every single picture instead I want to map through them like I currently am and have it work.
I tried creating a .env with PUBLIC_URL="." and PUBLIC_URL=. both did not work.
I tried deleting the homepage from my json already and it did not work.
Code: My JSON file named product-data.json for Reference I am not including every single item here for easier viewing but I have 84 of them altogether:
[
{
"id": "1",
"rating": 5,
"category": "shoes",
"price": 91,
"item": "adidas D.O.N. Issue #2 Marvel Venom",
"slug": "adidas-don-issue-2-marvel-venom",
"img": "./images/venom.png",
"link": "https://stockx.com/adidas-don-issue-2-marvel-venom?size=11",
"color": "black",
"countInStock": 10,
"brand": "Adidas",
"numReviews": 10,
"description": ""
},
{
"id": "2",
"rating": 4,
"price": 130,
"category": "shoes",
"item": "adidas Ultra 4D ASU",
"slug": "adidas-ultra-4d-asu",
"img": "./images/asushoe.png",
"link": "https://stockx.com/adidas-ultra-4d-arizona-state?size=11",
"color": "red",
"countInStock": 10,
"brand": "Adidas",
"numReviews": 10,
"description": ""
},
{
"id": "3",
"rating": 3.8,
"price": 80,
"category": "shoes",
"item": "adidas ZX 8000 LEGO",
"slug": "adidas-zx-8000-lego",
"img": "./images/Lego.png",
"link": "https://stockx.com/adidas-zx-8000-lego?size=11",
"color": "white",
"countInStock": 10,
"brand": "Adidas",
"numReviews": 10,
"description": ""
},
{
"id": "4",
"rating": 4.8,
"price": 177,
"category": "shoes",
"item": "adidas Dame 8 Battle Of The Bubble",
"slug": "adidas-dame-8-battle-of-the-bubble",
"img": "./images/adidas-Dame-8-Battle-Of-The-Bubble.png",
"link": "https://stockx.com/adidas-dame-8-battle-of-the-bubble?size=11",
"color": "blue",
"countInStock": 10,
"brand": "Adidas",
"numReviews": 10,
"description": ""
},
{
"id": "5",
"rating": 3.6,
"price": 116,
"category": "shoes",
"item": "adidas Harden Vol. 4 McDonald's",
"slug": "adidas-harden-vol-4-mcdonalds",
"img": "./images/adidas-harden-McDonalds.png",
"link": "https://stockx.com/adidas-harden-vol-4-mcdonalds?size=11",
"color": "purple",
"countInStock": 10,
"brand": "Adidas",
"numReviews": 10,
"description": ""
},
]
ProductCardListing.jsx
import productData from "../product-data.json";
import { ProductCard } from "./index";
import { FilterProducts } from "../utils/filter-products";
import { useFilter } from "../utils/filter-context";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
function ProductCardsListing() {
const { state } = useFilter();
return (
<div className="products-page">
<br />
<br />
<br />
<h3>
Showing {FilterProducts(productData, state).length} out of
{productData.length}
</h3>
<div className="product-cards">
<Row>
{FilterProducts(productData, state).map(
({ id, img, item, price, color, link, rating }) => (
<Col key={id}>
<ProductCard
key={id}
image={img}
item={item}
rating={rating}
price={price}
// color={color}
link={link}
/>
</Col>
)
)}
</Row>
</div>
</div>
);
}
export { ProductCardsListing };
ProductCard.jsx
import React from "react";
import { Card, ListGroup } from "react-bootstrap";
import Rating from "../Rating";
function ProductCard({
id,
image,
item,
rating,
link,
brand,
price,
// size,
color,
}) {
return (
<Card className="product" key={id}>
<img src={image} className="card-img-top" alt={item} />
<Card.Body>
<Card.Title className="product-link">{item}</Card.Title>
<Rating className="product-rating" rating={rating}></Rating>
<Card.Text>
{/* //on click open the stockx link in new tab (the logic for it comes from the product cards listing) */}
<a
className="product-price"
href={link ? link : { link }}
target="_blank"
rel="noreferrer"
>
StockX Price: {price}
</a>
</Card.Text>
<p className="product-rating">{color}</p>
<ListGroup.Item>
<div className="d-grid">
<button className="btn-primary">Add to cart</button>
</div>
</ListGroup.Item>
</Card.Body>
</Card>
);
}
export { ProductCard };
index.js (for the productCard, ProductCardListing, and the Sidebar)
import { ProductCard } from "./ProductCard";
import { ProductCardsListing } from "./ProductCardsListing";
import { Sidebar } from "./Sidebar";
export { ProductCard, ProductCardsListing, Sidebar };
I believe this is all the relevant code for this question but let me know if I need to include anything else. Thank you
It is not a good idea to use relative image url in your application. They depend on current location and it may lead to the errors. I would suggest placing images in CDN and using absolute urls. Another option is to change .json file to .js and import those images (then webpack will take care of them).
import venomSrc from './images/venom.png'
export default = [
{
"id": "1",
"rating": 5,
"category": "shoes",
"price": 91,
"item": "adidas D.O.N. Issue #2 Marvel Venom",
"slug": "adidas-don-issue-2-marvel-venom",
"img": venomSrc, // use here
"link": "https://stockx.com/adidas-don-issue-2-marvel-venom?size=11",
"color": "black",
"countInStock": 10,
"brand": "Adidas",
"numReviews": 10,
"description": ""
},
//...
Also you should setup PUBLIC_URL correctly and point it to github pages

How I can point src image tag to render image file from my local directory using json field in React?

I have very specific case on how I can render images using src. The case is that I have flask app returning json objects
{
"filepath": "0.jpg",
"group": "terminator",
"id": "0",
"isClicked": false,
"title": "image_0"
},
{
"filepath": "1.jpg",
"group": "terminator",
"id": "1",
"isClicked": false,
"title": "image_1"
}
and in the file directory I have images folder outside the react app
The question is how I can set the img src to render the images of the images folder, I have tried
<ul>
{Object.values(items).map((item) => (
<div key={item.id}>
<li>
{item.group} {item.title}
</li>
<img src={item.filepath} alt={item.title}/>
</div>
))}
</ul>
it render the group and title but not the img, then I tried to set a relative path like this
<img src={../../images/${item.filepath}} />
and it didn't work. please help thanks
oh, I just did this
<img src={require(`../../images/${item.filepath}`).default} />
and it worked

using axios and Redux to manage JSON data

I have a JSON file in the public folder and would like to use the data throughout the react app. I'm using axios in App.js but don't know the best way to store the data received in the state. I was going to use props but there is a lot of data being returned so that's probably not the best idea. So I thought of using axios in each component (Home, About, Posts, Footer, and Aside) but that wouldn't make sense either because data is meant to flow from app.js to children, and I don't want to repeat code. This led me to google search for solutions using Redux, I haven't come across any potential articles or videos explaining how to use Axios with Redux. My question is is there a way to manage JSON data in Redux or another state management library?
App.js
function App() {
const [data, setData] = useState({});
useEffect(() => {
axios.get('data/data.json')
.then(res => setData(res.data))
.catch(err =>console.log(err))
},[])
return (
<Router>
<header>
<div className="container container-flex">
<div className="site-title">
<h1>{data.title}</h1>
<p className="subtitle">{data.subtitle}</p>
</div>
<nav>
<ul>
<li><Link className="current-page" to="/">home</Link></li>
<li><Link to="/about">about me</Link></li>
<li><Link to="/posts">recent posts</Link></li>
</ul>
</nav>
</div>
</header>
<div className="container container-flex">
<Routes>
<Route path="/" element={<Home />}/>
<Route path="/about" element={<About />}/>
<Route path="/posts" element={<Posts />}/>
<Route path="*" element={<Error />}/>
</Routes>
<Aside />
</div>
<Footer/>
</Router>
);
}
export default App;
HOME.js
const Home = () => {
// const [data, setData] = useState({});
// useEffect(() => {
// axios.get('data/data.json')
// .then(res => setData(res.data))
// .catch(err =>console.log(err))
// },[])
// console.log(data.articlemain1.title)
return (
<>
<main role="main">
<article className="article-featured">
<h2 className="article-title">{articleman1.title}</h2>
<img className="article-image" src={articleman1.image} alt={articleman1.alt}/>
<p className="article-info">{articleman1.info}</p>
<p className="article-body">{articleman1.body}</p>
<a className="article-read-more" href="https://www.github.com/jerrellbryant"></a>
</article>
<hr>
</hr>
</main>
</>
)
}
export default Home
Data.json
{
"title": "Living the simple life",
"subtitle": "a blog exploring minimalism in life",
"articlemain1": {
"title": "Finding simplicity in life",
"image": "img/life.jpg",
"alt": "Clock plant and lamp on a desk",
"info": "Feburary 21, 2022",
"body": "\n <strong>Life can get complicated really quickly</strong>, but it doesn't have to be!\n There are many ways to simplify your life, <a class='article-link' href='#'> a few of which we've explored in the past</a>.\n This week we're taking a bit of a approach though, in how you can find simplicity in the life you already living.",
"anchor": "Continue Reading"
},
"articlesecondary1": {
"image": "img/life.jpg",
"alt": "Clock plant and lamp on a desk",
"info": "Feburary 21, 2022",
"comments": "3 comments"
},
"articlemain2": {
"title": "Keeping cooking simple",
"body": "\n Food is a very important part of everyone's life.\n If you want to be healthy, you have to eat healthy.\n One of the easiest ways to do that is to keep your cooking nice and simple.",
"anchor": "Continue Reading"
},
"articlesecondary2": {
"image": "img/food.jpg",
"alt": "dumplings with chop sticks",
"info": "July 12, 2021",
"comments": "5 comments"
},
"articlemain3": {
"title": "Simple decoractions",
"body": "\n A home isn't a home until you've decorated a little.\n People either don't decorate, or they go overboard and it doesn't have the impact they were hoping for. \n Staying simple will help draw the eye where you want it to and make things pop like never before.",
"anchor": "Continue Reading"
},
"articlesecondary3": {
"image": "img/deco.jpg",
"alt": "plant in water bowl",
"info": "June 15, 2021",
"comments": "9 comments"
},
"articlemain4": {
"title": "Simplicity and work",
"body": "\n Work is often a major source of stress.\n People get frustrated,it ruins their relationship with others and it leads to burnout. \n By keeping your work life as simple as possible, it will help balance everything out.",
"anchor": "Continue Reading"
},
"articlesecondary4": {
"image": "img/work.jpg",
"alt": "desk chair with a white table",
"info": "May 7, 2021",
"comments": "6 comments"
},
"widgettitle1": "About Me",
"widgettitle2": "Recent Posts",
"image": "img/aboutme.jpg",
"alt": "author smiling",
"body": "I find life better, and I'm happier, when things are nice and simple.",
"widgetpost1": {
"title": "Keeping cooking simple",
"image": "img/food.jpg"
},
"widgetpost2": {
"title": "Simplicity and work",
"image": "img/work.jpg",
"alt": "dumplings with chop sticks"
},
"widgetpost3": {
"title": "Simple decorations",
"alt": "plant in water bowl",
"image": "img/deco.jpg"
},
"footer": {
"website": "Living the Simple Life",
"copyright": "Copyright 2022"
}
}
You could move the JSON out of the public folder and just import it into your app.
If you want to do it in redux using axios then having an action handle the API call is the best way to do it.
I would also look at replacing axios with fetch as it will save you an import or two.

How can I get the index of a ordered list in a Rich Text in Contentful (Gastsby)

I'm working on a Gatsby project that uses Contentful as its headless CMS - and rendering a particular rich text field is driving me insane.
This is an example of the document I'm trying to render - It's basically an ordered list:
{
"nodeType": "document",
"data": {},
"content": [
{
"nodeType": "ordered-list",
"content": [
/* item 1 */
{
"nodeType": "list-item",
"content": [
{
"nodeType": "paragraph",
"content": [
{
"nodeType": "text",
"value": "Lorem 1.",
"marks": [],
"data": {}
}
],
"data": {}
}
],
"data": {}
},
/* item 2 */
{
"nodeType": "list-item",
"content": [
{
"nodeType": "paragraph",
"content": [
{
"nodeType": "text",
"value": "Lorem 2",
"marks": [],
"data": {}
}
],
"data": {}
}
],
"data": {}
},
],
"data": {}
}
]
}
And I want to render it on my Gatsby project without it's ol and li tags, like this:
<div class="single-instruction">
<header>
<p>Step 1</p>
<div></div>
</header>
<p>Lorem 1.</p>
</div>
<div class="single-instruction">
<header>
<p>Step 1</p>
<div></div>
</header>
<p>Lorem 2.</p>
</div>
Following Contentful's docs, I'm trying to render this using the #contentful/rich-text-types package. This is how far I managed to get:
import { BLOCKS } from "#contentful/rich-text-types";
import { renderRichText } from "gatsby-source-contentful/rich-text";
const options = {
renderNode: {
[BLOCKS.LIST_ITEM]: (node, children) => (
<div className="single-instruction">
<header>
<p>step </p>
<div></div>
</header>
{children}
</div>
),
},
};
renderRichText(instructions, options)
Which, of course, doesn't render the step number.
I feel I'm so close now! But for the life of me, I can't seem to find the right way to render the ordered list item index. Which is something I would easily get if this were an array that I could simple map.
Does anyone know what I'm missing here?
I have been facing the same issue. I used the counter-increment and counter css properties to generate the step numbers.
.instructions {
counter-increment: step;
}
.single-instruction .step::after {
content: counter(step);
}
<div class="instructions">
This is one list
<div class="single-instruction">
<header>
<p class="step"></p>
<div></div>
</header>
children
</div>
<div class="single-instruction">
<header>
<p class="step"></p>
<div></div>
</header>
children
</div>
</div>
<div>
This is another list
<div class="single-instruction">
<header>
<p class="step"></p>
<div></div>
</header>
children
</div>
<div class="single-instruction">
<header>
<p class="step"></p>
<div></div>
</header>
children
</div>
</div>
In this case you could use the CSS counter() variable to add step numbers via CSS.
So your CSS might look something like:
.single-instruction {
counter-reset: section;
}
.single-instruction p:after {
counter-increment: section;
content: counter(section);
}
The code above will add the counter on each paragraph (for the header paragraph content and the actual content paragraphs), so you'll need to add a custom class for the paragraph tags you want to target.
The only caveat is that I'm not sure how well this will work with screen readers and other assistive technology without digging deeper.
More information here: https://www.w3schools.com/CSS/css_counters.asp

Render images in Array

I've a JSON Schema which has Array of images which I need to render into a carousel in ReactJS.
api.json
[
{
"id": "DR001",
"propertyFullName": "8838, Brook St, NY",
"propertyShortName": "Anchorage, AK 99501",
"features": ["2 beds", "1 bath", "865 sqft"],
"description": "data.",
"images": [
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide1",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide2",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide3",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide4",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide5",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide6"
],
"status": true
},
{
"id": "DR002",
"propertyFullName": "8838, Brook St, NY",
"propertyShortName": "Anchorage, AK 99501",
"features": ["2 beds", "1 bath", "865 sqft"],
"description": "data.",
"images": [
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide1",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide2",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide3",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide4",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide5",
"http://placehold.it/1000x400/ffffff/c0392b/&text=slide6"
]
}
]
I am hard-coding the first array i.e. features like this
{APIData.map((apiData, index) => {
return (
<>
<Heading subtitle>
<span name={index}>{apiData.features[0]}</span>
<span class="middle-dot" aria-hidden="true">
</span>
<span>{apiData.features[1]}</span>
<span class="middle-dot" aria-hidden="true">
</span>
<span>{apiData.features[2]}</span> <br />
<span>
<p>{apiData.description}</p>
</span>
</Heading>
<hr />
</>
);
})}
Because, I know there will be only 3 features, but in case of images, it is dynamic. How come I overcome this?
The images are rendering in an other <div>, I've tried something like this
<Carousel {...settings}>
{APIData.map((images, index) => {
return (
<>{<img src={images.images} alt={index} />}</>
);
})}
</Carousel>
Using the code you already had, it will end up something like this to iterate through the images for every property:
<Carousel {...settings}>
{APIData.map((data, index) => {
data.images.map((image, index) => {
return <img key={index} src={image} alt={index} />
}
})}
</Carousel>
You can have a stateless component and render it inside the original map, like this
const Images = ({list}) => list.map(image => <img src={image}/>);
myArr.map(item => // some DOM here, and, at last: <Images list={item.images}>)
You know, not to repeat a map call inside another one, which, in my opinion, looks a bit ugly

Resources