Rendering Array of Images in React [duplicate] - arrays

This question already has answers here:
Loop inside React JSX
(84 answers)
Closed 2 years ago.
I need help. I have been searching similar posts, but none of them solved my problem (imagesPool.js)
import React from 'react';
const imagesPool = [
{ src: './images/starbucks.png'},
{ src: './images/apple.png'},
{ src: './images/mac.png'}
];
export default imagesPool;
Rendering the images (App.js) :
import React from "react";
import imagesPool from './imagesPool';
const App = () => {
return (
<div>
<img src={imagesPool} />
</div>
)};
export default App;
Result : No images being displayed

You should loop through your images because src expects a string location to the image.
import imagesPool from './imagesPool';
const App = () => {
return (
<div>
{imagesPool.map((imgSrc, index) => (<img src={imgSrc.src} key={index} alt="Make sure to include a alt tag, because react might throw an error at build"/>))}
</div>
)};

In react you solve things like conditionals, iterating, etc. with javascript (Remember, <img> is also just javascript and gets parsed into React.createElement("img")).
Since img expects a string in the src-property, we need to iterate over the array of sources and produce an img-Element for every source:
<div>
{
imagesPool.map(({ src }) => (<img key={src} src={src} />))
}
</div>
With key you tell react how to recognize that an element is the same with subsequent renderings.

You always need to import React from 'react' if you are rendering jsx/tsx. In your code, you are returning jsx, thus you need to import react.
import React from 'react';
import imagesPool from './imagesPool';
const App = () => {
return (
<div>
{imagesPool.map((image) => <img key={image.src} src={image.src} />)}
</div>
)};
export default App;

Related

React & Typescript Issue: trigger elements with InsertionObserver using props and manage them in other component

Small premise: I'm not a great Typescript expert
Hi everyone, I'm working on my personal site, I decided to develop it in Typescript to learn the language.
My component tree is composed, as usual, of App.tsx which render the sub-components, in this case Navbar.jsx and Home.jsx.
Below is the App.jsx code:
import './App.css';
import { BrowserRouter as Router, useRoutes } from 'react-router-dom';
import Home from './components/Home';
import Navbar from './components/Navbar';
import { useState } from 'react';
function App(){
const [navbarScroll,setNavbarScrool]=useState(Object)
const handleLocationChange = (navbarScroll : boolean) => {
setNavbarScrool(navbarScroll)
return navbarScroll
}
const AppRoutes = () => {
let routes = useRoutes([
{ path: "/", element: <Home handleLocationChange={handleLocationChange}/> },
{ path: "component2", element: <></> },
]);
return routes;
};
return (
<Router>
<Navbar navbarScroll={navbarScroll}/>
<AppRoutes/>
</Router>
);
}
export default App;
Here, instead, the Home.jsx code:
import { useInView } from 'react-intersection-observer';
import HomeCSS from "../styles/home.module.css"
import mePhoto from "../assets/me.png"
import { useEffect, useState } from 'react';
interface AppProps {
handleLocationChange: (values: any) => boolean;
}
export default function Home(props: AppProps){
const { ref: containerChange , inView: containerChangeIsVisible, entry} = useInView();
useEffect(()=>{
props.handleLocationChange(containerChangeIsVisible)
//returns false at first render as expected
console.log("Home "+containerChangeIsVisible)
},[])
return(
<>
<div className={`${ HomeCSS.container} ${containerChangeIsVisible? HomeCSS.container_variation: ''}`}>
<div className={HomeCSS.container__children}>
{/* when i scroll on the div the css change (this works)*/}
<h1 className={`${ HomeCSS.container__h1} ${containerChangeIsVisible? HomeCSS.container__h1_variation: ''}`}>My<br/> Name</h1>
<p>Computer Science student.</p>
</div>
<img src={mePhoto} className={HomeCSS.image_style}/>
</div>
<div ref={containerChange} style={{height:800,background:"orange"}}>
<p style={{marginTop:20}}>HIII</p>
</div>
</>
)
}
And Navbar.jsx:
import NavbarCSS from "../styles/navbar.module.css"
import acPhoto from "../assets/ac.png"
import { Link } from "react-router-dom";
import { useEffect, useState } from "react";
interface NavbarScroolProp{
navbarScroll:boolean
}
export default function Navbar(props:NavbarScroolProp){
const [scrollState,setScrollState]=useState(false)
const [pVisible,setpVisible] = useState('')
useEffect(()=>{
setTimeout(() => {
setpVisible("")
}, 3000)
setpVisible("100%")
},[])
//returns false also when should be true
console.log(props.navbarScroll)
return (
<>
{/*the props is undefined so the css doesn't change, i need to do this*/}
<nav className={`${props.navbarScroll?NavbarCSS.nav__variation:NavbarCSS.nav}`}>
<div className={NavbarCSS.nav_row}>
<div className={NavbarCSS.nav_row_container}>
<img src={acPhoto} className={NavbarCSS.image_style}/>
<p className={NavbarCSS.p_style} style={{maxWidth: pVisible}}>My name</p>
</div>
<div className={NavbarCSS.nav_row_tagcontainer}>
<Link className={NavbarCSS.nav_row_tag} to="/"> Home</Link>
<Link className={NavbarCSS.nav_row_tag} to="/"> About</Link>
<Link className={NavbarCSS.nav_row_tag} to="/"> Contact</Link>
</div>
</div>
</nav>
</>
);
}
In my application I want to change the background color whenever the div referring to the InsertionObserver ( I use "useInView" hook , from :https://github.com/thebuilder/react-intersection-observer) is displayed. The problem is that the div in question is in the Home.jsx component and I need to change the color of the divs in the navbar as well when the div in Home is triggered(or other components in case I need to in the future).
The question is: How can I dynamically trigger DOM elements of other components (to then perform certain operations) using the InsertionObserver ?
As you can see from the code I tried to create Props, but everything returns undefined and doesn't involve any changes.
I've tried without useEffect, without using the useInView hook, passing the object instead of the boolean value, but I can't find any solutions to this problem.
You would be of great help to me.
PS: I would like to leave the Navbar.jsx component where it is now, so that it is visible in all components.
Any advice or constructive criticism is welcome.

React dynamically add image

I am trying to add images dynamically from the assets folder in my react component. This is the code that I have:
import React from 'react';
const card = (props) => {
const image = require.context(
`../../assets/imgs`,
true,
new RegExp(`(${props.vnum}_${props.snum}.png)$`)
);
return (
<div>
<img src={image} alt="image" />
<p>{props.english}</p>
<p>{props.french}</p>
</div>
);
};
When I do this, I get the following error:
TypeError: webpack_require(...).context is not a function
I used CRA and looking up past posts I see that this should work. Where am I going wrong?
This should be enough.
import React from 'react';
const Card = (props) => {
return (
<div>
<img alt="image" src={require(`../../assets/imgs/${props.vnum}_${props.snum}.png`} />
<p>{props.english}</p>
<p>{props.french}</p>
</div>
);
};
It's necessary to use it in those convention?
The simpler solution without require.context()
import React from 'react';
import Image from "../../assets/img/english
import Image from "../../assets/img/french
const card = (props) => {
return (
<div>
<img src={english} alt="image" />
<p>{props.english}</p>
<img src={french} alt="image" />
<p>{props.french}</p>
</div>
);
};
Also:
It's possible to add some conditional rendering here (depends on variable render english or french) - i'm not sure You need it.
require.context is a special feature supported by webpack's compiler that allows you to get all matching modules starting from some base directory. The intention is to tell webpack at compile time to transform that expression into a dynamic list of all the possible matching module requests that it can resolve, in turn adding them as build dependencies and allowing you to require them at runtime.
So if regex matches more than 1 element - mapping is needed - however i think in this specific issue import is enough.
you can use simply require()
import React from "react";
import "./styles.css";
import Card from "./card";
export default function App() {
return (
<div className="App">
<h1>Hello</h1>
<h2>check this!</h2>
<Card vnum={12} snum={13} english={"english"} />
</div>
);
}
card.js
import React from "react";
export default function card(props) {
const image = require(`./img/${props.vnum}_${props.snum}.jpg`);
return (
<div>
<img src={image} alt="image1" width="200px" />
<p>{props.english}</p>
</div>
);
}
you can check this at here https://codesandbox.io/s/elegant-ramanujan-5qwcp
This is not the exact anser for your question, but might help you in later scenes maybe you may already know about this. If you have got URL's of the image that can be grabbed from internet, then you can save them into an array. Eg: const array = ['url1', 'url2',....etc]
Then use : array.map(url => { <img src={url} /> })
Also if you are pulling from an API use the same method.

How to refactor react hooks nested function properly

I have a function component which uses two states and both are changed based on event triggered.
I've read on react docs that is a bad idea to change states in nested function or condition. I also seen some examples using useEffects, but I have no clear idea how to properly refactor this.
here is my entire component:
import React, { useState, useEffect } from 'react'
import './App.css'
import AppHeader from '../app-header'
import AppFooter from '../app-footer'
import SearchInput from '../search-input'
import Stats from '../stats'
import Chart from '../chart'
import { getBundleInfoAPI } from '../../services/hostApi'
import 'react-loader-spinner/dist/loader/css/react-spinner-loader.css'
import Loader from 'react-loader-spinner'
function App() {
const [isSpinnerVisible, setSpinnerVisible] = useState(false)
const [bundleData, setBundleData] = useState({})
const _handleOnItemSelected = (item) => {
if (item && item.package && item.package.name && item.package.version) {
setSpinnerVisible(true)
getBundleInfoAPI(item.package.name, item.package.version)
.then(resposeData => setBundleData(resposeData))
.finally(() => setSpinnerVisible(false))
} else {
// TODO - implement an error handler component?
console.warn('WARNING: The selected bundle does not have name or version!')
}
}
return (
<div className="app">
<AppHeader />
<main>
<SearchInput onItemSelected={_handleOnItemSelected} />
<div className="app-main-inner-container">
<Loader type="Triangle" color="#00BFFF" height={200} width={200} visible={isSpinnerVisible} />
{!isSpinnerVisible &&
<div className="app-stats-chart-container">
<section className="app-stats-container"><Stats size={bundleData.stats} /></section>
<section className="app-chart-container"><Chart bundleChartData={bundleData.chart} /></section>
</div>
}
</div>
</main>
<AppFooter />
</div>
)
}
export default App
Docs section you are referring to means you must not put line with useState inside of nested functions, conditions, loops.
Calling setter returned by hook is definitely fine and correct.
This is fine, you are showing the loading screen when starting fetch and then hiding it when the fetch is done... no refactoring needed

How to transform anchor links from WP API into Next.js <Links> using `dangerouslySetInnerHTML`

I'm using a headless approach for a React (Next.js) + Wordpress API app.
The problem I'm running into is when the content editor adds an anchor tag into WP's WYSIWYG editor. I'm parsing that content using React's dangerouslySetInnerHTML and therefore a plain <a href="whatever"> is generated.
How do I go about transforming that into a next.js <Link> tag?
Not sure if this helps, but this is a piece of my code:
<React.Fragment>
<h1>Page: {title.rendered}</h1>
<div
className="richtext"
dangerouslySetInnerHTML={{ __html: content.rendered }}
></div>
{wpData.acf.modules.map((mod, index) => (
<React.Fragment key={`module=${index}`}>
{renderComponents(mod)}
</React.Fragment>
))}
</React.Fragment>
Since I'm using a decoupled solution, the anchor tag points to the server url, which leads to a broken page.
Ok, so the solution I found was posted here: https://stackoverflow.com/a/51570332/11983936
Basically factored the content display into its own helper function and used that in the components I need:
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { useRouter } from 'next/router';
import fixLink from './fixLink';
const useRenderRichtext = props => {
const router = useRouter();
const handleAnchorClick = e => {
const targetLink = e.target.closest('a');
if (!targetLink) return;
e.preventDefault();
const redirectThis = fixLink(targetLink.href);
router.push(`/${redirectThis}`);
};
return (
<Fragment>
<div
onClick={handleAnchorClick}
onKeyPress={handleAnchorClick}
className="richtext"
dangerouslySetInnerHTML={{ __html: props }}
></div>
</Fragment>
);
};
export default useRenderRichtext;

Is there a way in React Javascript to pass props and use it in external import?

I want to pass props from one component to another, and use it in the second one for an import above the component declaration
This is for using the same component, with no need to create it 4 times, every time with another SVG.
I'm using React, Javascript, Webpack, babel.
I'm also using svgr/webpack to create a component from an SVG picture, and it's crucial for me to use SVG not < img >.
import React from 'react';
import RightNavItem from './right_nav_item';
const RightNav = ({navitems}) => {
const rightNavItems = navitems.map( (item) => {
return <RightNavItem name={ item }/>
});
return(
<div className="rightnav">
{rightNavItems}
</div>
);
};
.
export default RightNav;
import React from 'react';
const RightNavItem = ({ name }) => {
const svgpath = `../../../../resources/img/navbar/${name}.svg`;
return(
<div>
<img src={ svgpath } style={{height: '25px'}}/>
<span>{ name }</span>
</div>
);
};
export default RightNavItem;
And I want to achieve being able to do this:
import React from 'react';
import SvgPicture from '../../../../resources/img/navbar/{name}.svg';
const RightNavItem = ({ name }) => {
return(
<div>
<SvgPicture />
<span>{ name }</span>
</div>
);
};
export default RightNavItem;
.
Ok so I went back and implemented the whole thing on my local app to get exactly what you need. I am editing my original answer. Hope this solves your issue.
The parent:
import React from 'react';
import { ReactComponent as svg } from 'assets/img/free_sample.svg';
import RightNavItem from './RightNavItem';
const LOGOS = [
{ name: 'home', svg },
{ name: 'home', svg },
];
const RightNav = () => (
<div>
{LOGOS.map(logo => (
<RightNavItem name={logo.name}>
<logo.svg />
</RightNavItem>
))}
</div>
);
export default RightNav;
The child:
import React from 'react';
const RightNavItem = ({ name, children }) => (
<div>
{children}
<span>{name}</span>
</div>
);
export default RightNavItem;
You don't need to import the svg as I did, if you are able to use svg as a component in your webpack config then continue to do what you were doing before.
I managed to do it in a kind of ugly way, but it works.
The problem is if I have more than 4 items, then using it without the map() function can be really annoying.
I used {props.children}, and instead of using map(), I added the 4 times, each with different 'SVG' component child and different props 'name', that way the component only gets initialized at the RightNavItem level.
IF SOMEONE KNOWS how can I use this with the map() function, It'll help a lot!
Thanks to everyone who helped!
For example:
const RightNav = (props) => {
return(
<div className = "rightnav">
<RightNavItem name = {home}>
<HomeSVG />
</RightNavItem>
<RightNavItem name = {profile}>
<ProfileSVG />
</RightNavItem>
.
.
.
</div>
);
};
And in the RightNavItem:
const RightNavItem = (props) => {
return(
<div>
{props.children}
<span>{ props.name }</span>
</div>
);
};

Resources