user17969172
user17969172

Reputation:

react onClick always only select last element

I was trying to do a onClick function inside navbar component but i noticed everytime the onclick function only works on the last element of the list. It does not matter which element i click on it always affects the last element only. Here's my Navbar component and listItem component -

Navbar:

import './Navbar.scss';
import ListItem from '../ListItem/ListItem';
import { navLinks } from '../../staticData';
import { useRef } from 'react';

const Navbar = () => {
    const itemRef = useRef();
    const handleClick = () => {
        itemRef.current.style.background = 'red'
    };

  return (
    <div className='navbar'>
        <ul className="navbarList">
            {
                navLinks.map((item, index) => (
                    <ListItem item={item} key={index} onClick={handleClick} itemRef={itemRef}/>
                ))
            }
        </ul>
    </div>
  )
}

export default Navbar

listItem Component:

import './ListItem.scss';
import { Link } from 'react-router-dom';

const ListItem = ({ item, onClick, itemRef }) => {
  return (
    <Link onClick={onClick} ref={itemRef} className='listItemWrapper' to=''>
      <li className="listItem">{item.name}</li>
    </Link>
  )
}

export default ListItem

Example - Example Image

Upvotes: 0

Views: 798

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370699

itemRef will only hold a reference to one element. Here, it'll be the last one because that's the past ListItem for which itemRef was passed down.

This is not a good place for a ref anyway, plus, you should be avoiding native DOM methods in React whenever possible. Change state on click instead, and pass that state down to the ListItem so it can determine whether to color the background or not.

const Navbar = () => {
    const [clickedArr, setClickedArr] = useState(() => navLinks.map(() => false));
    return (
        <div className='navbar'>
            <ul className="navbarList">
                {
                    navLinks.map((item, index) => (
                        <ListItem
                            item={item}
                            key={index}
                            clicked={clickedArr[index]}
                            onClick={() => {
                                setClickedArr(clickedArr.map((existing, i) => i === j ? true : existing));
                            }}
                        />
                    ))
                }
            </ul>
        </div>
    )
}
const ListItem = ({ item, onClick, clicked }) => {
    return (
        <Link onClick={onClick} ref={itemRef} className='listItemWrapper' to='' style={clicked ? { backgroundColor: 'red' } : null}>
            <li className="listItem">{item.name}</li>
        </Link>
    )
}

Upvotes: 2

Related Questions