使用useState和onClick与React更改背景图像 [英] Changing background image using useState and onClick with React
问题描述
我一直在努力使这项工作顺利进行.我的目标是要在单击链接后在链接后面显示背景图像.单击时,导航上的每个链接都有其自己的图像.我遇到的第一个错误是重新渲染过多.我更多地操作了代码,错误消失了,但是图像仍然无法呈现onClick.可以提供的任何帮助将不胜感激,我对React还是一个新手,很想了解我做错了什么.谢谢!
I have been going in circles trying to make this work. My goal is to have a background image that displays behind a link after it is clicked. Each Link on my Navigation has its own image for when clicked. The first error I was experiencing was too many re-renders. I manipulated the code more, the error went away however the images are still not rendering onClick. Any help that can be provided would be greatly appreciated, I am still pretty new to React and would love to understand what I am doing wrong. Thank you!
import { Link } from 'react-router-dom'
import { useState } from 'react'
import Logo from '../../assets/images/Platform-Logo.svg'
import artistPaintBackground from '../../assets/images/Navigation-Artists-SVG.svg'
import eventsPaintBackground from '../../assets/images/Navigation-Events.svg'
import contactUsPaintBackground from '../../assets/images/Navigation-Contact-Us.png'
import homePaintBackground from '../../assets/images/Navigation-Home.png'
const navLinks = [
{
id: 0,
title: `HOME`,
path: `/`,
bgI: '',
},
{
id: 1,
title: 'EVENTS',
path: '/events',
bgI: '',
},
{
id: 2,
title: `ARTISTS`,
path: `/artists`,
bgI: '',
},
{
id: 3,
title: `CONTACT US`,
path: `/contactUs`,
bgI: '',
},
]
const Nav = (props) => {
const [navLinksBackgroundImage, setNavLinksBackgroundImage] = useState({
navLinks: [
{
id: 0,
title: `HOME`,
path: `/`,
bgI: '',
},
{
id: 1,
title: 'EVENTS',
path: '/events',
bgI: '',
},
{
id: 2,
title: `ARTISTS`,
path: `/artists`,
bgI: '',
},
{
id: 3,
title: 'CONTACT US',
path: `/contactUs`,
bgI: '',
},
],
})
const css = {
backgroundImage: `url(${navLinks.bgI})`,
width: '20%',
height: '100%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
}
const addBgIHandler = () => {
setNavLinksBackgroundImage({
navLinks: [
{
id: 0,
title: `HOME`,
path: `/`,
bgI: ` ${homePaintBackground}`,
},
{
id: 1,
title: 'EVENTS',
path: '/events',
bgI: `${eventsPaintBackground}`,
},
{
id: 2,
title: `ARTISTS`,
path: `/artists`,
bgI: `${artistPaintBackground}`,
},
{
id: 3,
title: 'CONTACT US',
path: `/contactUs`,
bgI: `${contactUsPaintBackground}`,
},
],
})
if (navLinks.id === 0) {
return `${homePaintBackground}`
} else if (navLinks.id === 1) {
return `${eventsPaintBackground}`
} else if (navLinks.id === 2) {
return `${artistPaintBackground}`
} else if (navLinks.id === 3) {
return `${contactUsPaintBackground}`
} else {
return null
}
}
return (
<div>
<AppBar position='static' className={classes.navBar}>
<Toolbar>
<Container maxWidth='xl' className={classes.navDisplayFlex}>
<Link to='/'>
<img className={classes.imageLogo} src={Logo} />
</Link>
<Hidden smDown>
<ThemeProvider theme={theme}>
<List
component='nav'
aria-labelledby='main-navigation'
className={classes.navDisplayFlex}
>
{navLinks.map(({ title, path, bgI }) => (
<Link
active={bgI}
to={path}
key={title}
value={bgI}
className={classes.linkText}
onClick={addBgIHandler}
style={css}
>
<ListItem disableGutters={true}>
<ListItemText primary={title} />
</ListItem>
</Link>
))}
</List>
</ThemeProvider>
</Hidden>
<Hidden mdUp>
<Dropdown navLinks={navLinks} />
</Hidden>
</Container>
</Toolbar>
</AppBar>
</div>
)
}
export default Nav
推荐答案
问题
此代码中有一些错误.我看到的第一个是在此行上:
Issues
There are a few errors in this code. The first one I see is on this line:
backgroundImage: `url(${navLinks.bgI})`,
navLinks
是一个 array
,因此它没有 bgI
属性.数组的各个元素是具有 bgI
属性的对象.
navLinks
is an array
, so it doesn't have a bgI
property. The individual elements of the array are objects with a bgI
property.
接下来令人困惑的是 addBgIHandler
函数.此函数调用 setNavLinksBackgroundImage
并将状态更新为每个链接具有其 bgI
的图像的状态.然后,它会处理一堆 if
/ else
个案例,并返回一个单个 bgI
.但是此返回值从未在任何地方使用.
The next confusing thing is the addBgIHandler
function. This function calls setNavLinksBackgroundImage
and updates the state to one where every link has an image for its bgI
. It then goes through a bunch of if
/else
cases and returns a single bgI
. But this returned value is never used anywhere.
通常,您希望以所需的状态存储最少的信息.如果某些事情永远不会改变,那么它就不必处于状态.我们唯一需要更改的信息是单击了哪个链接?
In general you want to store the minimal amount of information in state that you need. If something never changes then it doesn't need to be in state. The only changing information that we need to know here is which link was clicked?
我将在组件外部定义您的 navLinks
数组,但要对其进行更改,以使其每个图像都包含 bgI
.我们想知道每个链接的 bgI
,但这并不意味着我们将显示 bgI
.
I'm going to keep your navLinks
array defined outside of the component, but change it so that it includes the bgI
for every image. We want to know the bgI
for each link, but that doesn't mean we will show the bgI
.
我们将使用状态来告诉我们哪个链接(如果有)是活动链接.我正在使用 id
,但这没关系.您可以改用 title
或 path
.
We will use a state to tell us which link (if any) is the active link. I am using the id
but it doesn't matter. You could use the title
or the path
instead.
// Should the initial state be home? Or no active link? That's up to you.
const [activeLinkId, setActiveLinkId] = useState(0);
我们只会在链接为活动链接时显示背景图像.我们需要使它成为一个函数,而不是一个恒定的 css
,以便每个链接都可以使用不同的函数.我们将从 navLinks.map
内部调用此函数,以便我们可以传入所需的参数.我们需要 id
以便将其与 activeLinkId
状态进行比较,并需要 bgI
来设置背景图像(如果处于活动状态).
We will only show the background image on a link if it is the active link. Instead of a constant css
we will need to make it a function so that it can be different for each link. We are going to call this function from inside navLinks.map
, so we can pass in the arguments that we need. We will need the id
in order to compare it to the activeLinkId
state and the bgI
to set the background image if it's active.
我建议您移动样式 width:'20%',height:'100%'
,这些样式始终存在于您的 classes
对象中,并且仅用于处理这里的背景图片.
I would recommend that you move the styles width: '20%', height: '100%',
which are always present into your classes
object and just handle the background image here.
const createCss = (id: number, bgI: string) => {
if (id === activeLinkId) {
return {
backgroundImage: `url(${bgI})`,
backgroundSize: "cover",
backgroundRepeat: "no-repeat"
};
} else return {};
};
在我自己的代码中,我将使用三元运算符而不是 if
/ else
,但我想保持其清晰易读.
In my own code I would use a ternary operator instead of if
/else
but I want to keep this clear and readable.
在 Link
中,我们调用该函数来设置 style
道具.
In the Link
, we call the function to set the style
prop.
style={createCss(id, bgI)}
我们的新 addBgIHandler
非常简单,我们可以内联定义它.单击此链接后,我们将 activeLinkId
设置为此 id
.
Our new addBgIHandler
is so simple that we can define it inline. When this link is clicked, we set the activeLinkId
to this id
.
onClick={() => setActiveLinkId(id)}
代码
const navLinks = [
{
id: 0,
title: `HOME`,
path: `/`,
bgI: ` ${homePaintBackground}`
},
{
id: 1,
title: "EVENTS",
path: "/events",
bgI: `${eventsPaintBackground}`
},
{
id: 2,
title: `ARTISTS`,
path: `/artists`,
bgI: `${artistPaintBackground}`
},
{
id: 3,
title: "CONTACT US",
path: `/contactUs`,
bgI: `${contactUsPaintBackground}`
}
];
const Nav = (props) => {
// Should the initial state be home? Or no active link? That's up to you.
const [activeLinkId, setActiveLinkId] = useState(0);
const createCss = (id: number, bgI: string) => {
if (id === activeLinkId) {
return {
backgroundImage: `url(${bgI})`,
backgroundSize: "cover",
backgroundRepeat: "no-repeat"
};
} else return {};
};
return (
<div>
<AppBar position="static" className={classes.navBar}>
<Toolbar>
<Container maxWidth="xl" className={classes.navDisplayFlex}>
<Link to="/">
<img className={classes.imageLogo} src={Logo} />
</Link>
<Hidden smDown>
<ThemeProvider theme={theme}>
<List
component="nav"
aria-labelledby="main-navigation"
className={classes.navDisplayFlex}
>
{navLinks.map(({ title, path, bgI, id }) => (
<Link
to={path}
key={title}
className={classes.linkText}
onClick={() => setActiveLinkId(id)}
style={createCss(id, bgI)}
>
<ListItem disableGutters={true}>
<ListItemText primary={title} />
</ListItem>
</Link>
))}
</List>
</ThemeProvider>
</Hidden>
<Hidden mdUp>
<Dropdown navLinks={navLinks} />
</Hidden>
</Container>
</Toolbar>
</AppBar>
</div>
);
};
export default Nav;
反应路由器
我已经完全按照您提出的问题回答了这个问题,这是如何在单击链接时显示图像?" 但是我看到 Link
组件是从 react-router-dom
导入的,所以我认为您并不是在问正确的问题.问题应该是我如何显示当前页面链接的图像?" 该问题有一个完全不使用状态的答案.
React Router
I've answered the question exactly as you've presented it, which is "how do I show an image on a link when it's clicked?" But I see that the Link
component is imported from react-router-dom
so I think that you aren't asking the right question. The question should be "how do I show an image for the current page link?" That question has a different answer which doesn't use state at all.
您可以将 Link
组件替换为 NavLink
.
You can replace your Link
components with NavLink
.
< Link>
的特殊版本,当其与当前URL匹配时,它将为呈现的元素添加样式属性.
A special version of the
<Link>
that will add styling attributes to the rendered element when it matches the current URL.
这不是我们想要的吗?使用 NavLink
,我们可以放弃 useState
和 onClick
和 createCss
.相反,我们将背景样式设置为 activeStyle
道具,该道具仅在链接处于活动状态时才会应用这些样式.
Isn't that what we want? With NavLink
we can ditch the useState
and the onClick
and the createCss
. Instead we set our background styles to the activeStyle
prop, which will only apply these styles when the link is active.
{navLinks.map(({ title, path, bgI }) => (
<NavLink
to={path}
key={title}
className={classes.linkText}
activeStyle={{
backgroundImage: `url(${bgI})`,
backgroundSize: "cover",
backgroundRepeat: "no-repeat"
}}
>
这篇关于使用useState和onClick与React更改背景图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!