英文:
Change selected item color in material ui list button event
问题
I have sidebar with buttons, when i click on one i want to set color on selected button but it doesn't work properly because sometimes it requires clicking twice to set the color i don't know why. When i set setSelectedIndex(1) but in console.log(selectedIndex) shows 0
import { Drawer, List, ListItem, ListItemButton, ListItemText, styled, Toolbar } from '@mui/material';
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { sideItems } from './SideItems';
const Sidebar: React.FC = () => {
const drawerWidth = 240;
const navigate = useNavigate();
const [selectedIndex, setSelectedIndex] = useState(0);
const StyledListText = styled(ListItemText)({
textAlign: 'center',
color: 'white'
});
const CustomListButton = styled(ListItemButton)({
"&.Mui-selected": {
backgroundColor: "#2e8b57!important"
}
});
const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
event.preventDefault();
navigate(path);
setSelectedIndex(index);
}
return (
<Drawer
variant="permanent"
sx={{
width: drawerWidth,
[`& .MuiDrawer-paper`]: { width: drawerWidth, boxSizing: 'border-box' }
}}
PaperProps={{
elevation: 12,
sx: {
width: 240,
backgroundColor: "primary.light"
}
}}
>
<Toolbar />
<List>
{sideItems.map((item, index) =>
<ListItem key={item.id}>
<CustomListButton selected={index === selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}>
<StyledListText primary={item.text} />
</CustomListButton>
</ListItem>
)}
</List>
</Drawer>
)
}
export default Sidebar;
英文:
I have sidebar with buttons, when i click on one i want to set color on selected button but it doesn't work properly because sometimes it requires clicking twice to set the color i don't know why. When i set setSelectedIndex(1) but in console.log(selectedIndex) shows 0
import { Drawer, List, ListItem, ListItemButton, ListItemText, styled, Toolbar } from '@mui/material'
import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom';
import { sideItems } from './SideItems';
const Sidebar: React.FC = () => {
const drawerWidth = 240;
const navigate = useNavigate();
const [selectedIndex, setSelectedIndex] = useState(0);
const StyledListText = styled(ListItemText)({
textAlign: 'center',
color: 'white'
});
const CustomListButton = styled(ListItemButton)({
"&.Mui-selected": {
backgroundColor: "#2e8b57!important"
}
});
const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
event.preventDefault();
navigate(path);
setSelectedIndex(index);
}
return (
<Drawer
variant="permanent"
sx={{
width: drawerWidth,
[`& .MuiDrawer-paper`]: { width: drawerWidth, boxSizing: 'border-box' }
}}
PaperProps={{
elevation: 12,
sx: {
width: 240,
backgroundColor: "primary.light"
}
}}
>
<Toolbar />
<List>
{sideItems.map((item, index) =>
<ListItem key={item.id}>
<CustomListButton selected={index === selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}>
<StyledListText primary={item.text} />
</CustomListButton>
</ListItem>
)}
</List>
</Drawer>
)
}
export default Sidebar
答案1
得分: 1
大多数情况下,您正在将 <Sidebar/>
作为子组件包含在每个页面组件的 JSX 中,因此每次都会创建一个新实例,而且由于初始的 selectedIndex
值为 0,所以无论您使用 navigate
被重定向到哪个页面组件,它始终选择的是第一个项目,除非您单击另一个按钮来更新新 Sidebar
实例的 selectedIndex
值。
您应该在顶层使用 <Sidebar/>
,以便只创建一个实例,这样它就不会丢失其 hooks
值,类似于这样:
function Layout(props) {
return (
<Fragment>
<Sidebar/>
<main>{props.children}</main>
</Fragment>
);
}
function MyApp({ Component, pageProps }) {
return (
<Layout>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<Component {...pageProps} />
</Layout>
);
}
英文:
Most likely here you are including <Sidebar/>
as child component inside the jsx of every page component so each time you are creating a new instance of it and since the initial selectedIndex
value is 0 it is always the first item which is selected no matter to which page component you have been redirected with navigate
, unless you click on another button to update selectedIndex
value of this new Sidebar
instance.
What you should do it to use <Sidebar/>
on the top level to create only one instance of it, so it does not lose it's hooks
values something like this :
function Layout(props) {
return (
<Fragment>
<Siderbar/>
<main>{props.children}</main>
</Fragment>
);
}
function MyApp({ Component, pageProps }) {
return (
<Layout>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<Component {...pageProps} />
</Layout>
);
答案2
得分: 1
Solutions:
- 你可以写一个布尔型的解决方案:
(更改你的字符串)
const [selectedIndex, setSelectedIndex] = useState(true);
const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
event.preventDefault();
setSelectedIndex(!selectedIndex);
}
<CustomListButton selected={selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}></CustomListButton>
- 你可以写一个数字型的解决方案:
(更改你的字符串)
const [selectedIndex, setSelectedIndex] = useState(0);
const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
event.preventDefault();
setSelectedIndex((prev) => {
return prev ? 0 : 1;
});
}
<CustomListButton selected={!!selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}></CustomListButton>
英文:
You can write your question better:
- Don't need write in this example:
import { useNavigate } from 'react-router-dom';
import { sideItems } from './SideItems';
- You must in example write const sideItems
const sideItems = [
{
id: '1',
text: 'lalala',
path: 'lololo'
}
]
Solutions:
- You can write solution - boolean:
(change your strings)
const [selectedIndex, setSelectedIndex] = useState(true);
const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
event.preventDefault();
setSelectedIndex(!selectedIndex);
}
<CustomListButton selected={selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}>
- You can write solution - number:
(change your strings)
const [selectedIndex, setSelectedIndex] = useState(0);
const handleListItemClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, path: string, index: number) => {
event.preventDefault();
setSelectedIndex((prev) => {
return prev ? 0 : 1
});
}
<CustomListButton selected={!!selectedIndex} onClick={(event) => handleListItemClick(event, item.path, index)}>
答案3
得分: 1
感谢各位的帮助,我找到了解决方法。
我添加了以下代码:
import { Link } from 'react-router-dom';
其余部分如下:
{sideItems.map((item) =>
<ListItemButton sx={{
"&.Mui-selected": {
backgroundColor: "#2e8b57!important"
}
}} key={item.id} component={Link} to={item.path} selected={location.pathname === item.path}>
<StyledListText primary={item.text} />
</ListItemButton>
)}
英文:
Thank, you guys for help I found solution for my case
I added
import { Link } from 'react-router-dom';
and rest looks like
{sideItems.map((item) =>
<ListItemButton sx={{
"&.Mui-selected": {
backgroundColor: "#2e8b57!important"
}
}} key={item.id} component={Link} to={item.path} selected={location.pathname === item.path}>
<StyledListText primary={item.text} />
</ListItemButton>
)}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论