How to update image source on hover? - reactjs

I'm trying to use Next.js Image component to render images on my app page. I'm having issues understanding how to select and update the main Image src so that I can replace it with all the responsive sizes Next.js creates for Image elements.
I have a list of navigation links in my app menu and I want to assign data attributes to each one so that when these links are hovered over they update the main Image element and display a different main image for each link hovered over.
I'm new to React and the way it works, so I'm not sure what my issues are but I have made a start with some basic concepts. I have started to console log the data I have to see what I get but now I've hit a brick wall.
Here is what I have so far:
import React, { useState, useEffect, useRef } from 'react';
import Image from 'next/image';
function Header() {
const MenuHeroImg = useRef();
function handleMouseEnter(e) {
console.log(e.target.getAttribute('data-project-image-url'));
console.log(MenuHeroImg.current);
}
return (
<>
<ul>
<li
onMouseEnter={handleMouseEnter}
data-project-image-url="/public/images/projects/image_2.png"
className={`${navigationStyles['c-navigation-menu-link']}`}>
<Link href="/project-link-here">Link</Link>
</li>
<li
onMouseEnter={handleMouseEnter}
data-project-image-url="/public/images/projects/image_3.png"
className={`${navigationStyles['c-navigation-menu-link']}`}>
<Link href="/project-link-here_2">Link</Link>
</li>
<ul>
<picture ref={MenuHeroImg}>
<Image
src="/public/images/projects/image_1.png"
alt="Image"
width={660}
height={835}
layout="responsive"
/>
</picture>
</>
);
}
export default Header;
Console Log:

Rather than using data-* attributes to set the images paths, move the image source into a state variable that you can then update when each onMouseEnter gets triggered.
Also note that images in the public folder are referenced as /images/projects/image_1.png, without the /public.
import React, { useState } from 'react';
import Image from 'next/image';
function Header() {
const [image, setImage] = useState('/images/projects/image_1.png');
function handleMouseEnter(imagePath) {
return () => {
setImage(imagePath);
};
}
return (
<>
<ul>
<li
onMouseEnter={handleMouseEnter('/images/projects/image_2.png')}
className={`${navigationStyles['c-navigation-menu-link']}`}
>
<Link href="/project-link-here">Link</Link>
</li>
<li
onMouseEnter={handleMouseEnter('/images/projects/image_3.png')}
className={`${navigationStyles['c-navigation-menu-link']}`}
>
<Link href="/project-link-here_2">Link</Link>
</li>
<ul>
<Image
src={image}
alt="Image"
width={660}
height={835}
layout="responsive"
/>
</>
);
}
export default Header;

the src should be like this:/images/projects/image_1.png;
because nextjs look for the image in the root folder that is the public folder

Related

NextJs 13 Experimental App Dir Hash in routes not directing to the hash id

I am using Nextjs 13 with the experimental App Dir but am not sure if this problem I am facing has anything to do with the issue I am facing. I have an id in my home page of "faqs" and when I click on the link, I can see it successfully goes to that link but does nothing in the browser. If I am on another page, I click the link and it takes me to the home page with the correct url but still stays on the top of the page and does not scroll to the indicated id. I did implement scroll={false} as suggested in the documentation but it makes no difference.
Here is a snippet of the relevant code parts:
"use client"
import React, { useState } from "react"
import { useRouter } from "next/navigation"
import Link from "next/link"
const Navigation = () => {
const router = useRouter()
...
In the return:
<Link scroll={false} href="/#faqs">FAQS</Link>
I Even tried:
<button type="button" onClick={() => router.push("/#faqs")}>FAQS</button>
In React the hash works fairly well but in next js, even only in client rendering it seems convoluted. If anyone knows what I am doing wrong or if there is a viable work around, I would sure appreciate it.
Thank you in advance.
If I am missing anything, please let me know.
I use hashtags a lot and I plan to start using the app directory in future projects, so I dug into this and it's not pretty. Apparently, NextJS uses a different package for app directory components client-side called "next/navigation". It's very different from "next/router". Also, when using "next/link" elements, NextJS does not trigger the onRouteChangeComplete event when location.hash changes but location.pathname does not.
So, in order to detect a hash change and scroll to the associated element, I finally had to implement this hack:
"use client"
import { Inter } from '#next/font/google'
import paragraph from './paragraph'
import Link from 'next/link'
import { useEffect, useState } from 'react'
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
const [navClick, setNavClick] = useState(false);
useEffect(() => {
setTimeout(() => {
const hash = window.location.hash;
if (hash) document.querySelector(hash).scrollIntoView();
}, 0);
}, [navClick])
const toggleNavClick = () => setNavClick((oldVal) => !oldVal);
return (
<main>
<nav>
<ul>
<li>
<Link href="/#one" onClick={toggleNavClick}>Section One</Link>
</li>
<li>
<Link href="/#two" onClick={toggleNavClick}>Section Two</Link>
</li>
<li>
<Link href="/#three" onClick={toggleNavClick}>Section Three</Link>
</li>
</ul>
</nav>
<div className="container">
<section id="one">
<h1>Section One</h1>
<div dangerouslySetInnerHTML={{ __html: paragraph }} />
</section>
<section id="two">
<h1>Section Two</h1>
<div dangerouslySetInnerHTML={{ __html: paragraph }} />
</section>
<section id="three">
<h1>Section Three</h1>
<div dangerouslySetInnerHTML={{ __html: paragraph }} />
</section>
</div>
</main>
)
}
Since the hash change cannot be detected because no event is triggered, I basically created an event by toggling navClick each time a link is clicked. The navigation logic is enclosed in setTimeout() function because it triggers after window.location is updated.
Repo: https://github.com/designly1/next-hash-test
Demo: https://next-hash-test.vercel.app/

How to map React Icons in react

I have the icon imports above
import { MdSettings } from "react-icons/md";
import { RiAccountPinCircleFill } from "react-icons/ri";
import { BsSunFill } from "react-icons/bs";
then here is the array containing the imports
const Icons = ["MdSettings", "RiAccountPinCircleFill", "BsSunFill"];
I want to map it here
<div className="topbar-links inline-flex">
<ul>*this is where I want it rendered*</ul>
</div>
First of all, if your variable is not a component, you should avoid to use PascalCase for the name. So you can rename Icons as icons.
Then, you should store the elements imported directly in the array and not just their names as string, or you will not be able to use the components:
const icons = [MdSettings, RiAccountPinCircleFill, BsSunFill];
Finally, for the loop you can do like this:
<div className="topbar-links inline-flex">
<ul>
{icons.map((Icon, i) => (
<li key={i}>
<Icon />
</li>
))}
</ul>
</div>
If the icons are react components you can store the icons as
const Icons = [<MdSettings/>, <RiAccountPinCircleFill/>, <BsSunFill/>]
then you can map them as
<div className="topbar-links inline-flex">
<ul>{Icons.map((icon, index) => <li key={index}>{icon}</li>}</ul>
</div>

Why won't my React website display images?

I have a JS file; Cards.js which implements a card-style div:
import React from "react";
import CardItem from "./CardItem";
import "./Cards.css";
function Cards() {
return (
<div classNam="cards">
<ul className="cards__items">
<CardItem
src={require("../images/img-9.jpg").default}
text="text"
label="label"
path="/jobs"
/>
</ul>
</div>
);
}
export default Cards;
And then CardItem.js:
import React from "react";
import { Link } from "react-router-dom";
function CardItem(props) {
return (
<div>
<li className="cards__item">
<Link className="cards__item__link" to={props.path}>
<figure className="cards__item__pic-wrap"
data-category={props.label}>
<img
src={props.src}
className="card__item__img"
alt="alt"
/>
</figure>
<div className="cards__item__info">
<h5 className="cards__item__text">{props.text} </h5>
</div>
</Link>
</li>
</div>
);
}
export default CardItem;
However, on my site, the images from CardItem are not displayed. The Text, Label and Path all work, but no image.
I've looked around and have seen different solutions to this issue but none have worked for me.
I've tried using
src="../images/img-9.jpg"
instead of using require but that also didn't work.
What's weird is I can see the path AND the preview of the image when looking at the Chrome inspection panel, but they won't load.
I've also tried putting the images folder in the Public directory which is another solution I've seen, but I get an error saying something about loading resources outside of /src

How to display multiple images with uploaded file URL's?

I am working on a project that uploads images to Heroku with their new react-simple-file-upload addon. After uploading the file, a URL is provided for the image saved in the DB. I managed to display one of the images, but now I would like to display multiple-- essentially create a simple gallery. I am thinking i'll have to make a function that uses useState and an array, but am not really sure how to design it beyond that. Here is my working code:
import React from "react";
import SimpleFileUpload, { SimpleFileUploadProvider } from "../components/SimpleFileUpload"
import { useState } from 'react'
import "./styles.css"
const API_KEY = '...'
export default function About() {
const [files, setFiles] = useState();
console.log(files)
return (
<div className="App">
<h1>upload an image</h1>
<SimpleFileUpload apiKey={API_KEY} onSuccess={setFiles} />
{files && (
<div>
<img className="photo" src={files} witdh="50" hight="50" alt="huh?"/>
<div className="gallery">
</div>
</div>
)}
</div>
);
}
Any tips or tricks is greatly appreciated

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.

Resources