Home > Blockchain >  Change selected item color in material ui list button event
Change selected item color in material ui list button event

Time:02-06

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

CodePudding user response:

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>
  );

CodePudding user response:

You can write your question better:

  1. Don't need write in this example:
import { useNavigate } from 'react-router-dom';
import { sideItems } from './SideItems';
  1. You must in example write const sideItems
const sideItems = [
  {
    id: '1',
    text: 'lalala',
    path: 'lololo'
  }
]

Solutions:

  1. 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)}>
  1. 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)}>

  • Related