0

Beginner React developer here.

here is my state and function that toggles a ul from display:none to display:block

const [dropDown, setDropdown] = useState('hidden')
const [icon, setIcon] = useState('\u2795')

const handleHidden = () => {

if (dropDown === 'hidden') setDropdown('active')
if (dropDown === 'active') setDropdown('hidden')
if (icon === '\u2795') setIcon('\u2796')
if (icon === '\u2796') setIcon('\u2795')

}

the icons just toggle between a unicode "+" and "-"

and a corresponding onClick function to toggle between the two classes:

 <span onClick={() => handleHidden()} className='plus-minus'>{icon}</span></h3> 

in addition to this code I map through an array of students and diplay all their values in a div.

The problem is when I click the span all the items open and close (expectedly). what would be the next steps to having only the item that I click open and close while the rest stay hidden?

Ben Shekhtman
  • 385
  • 5
  • 15
  • Could you have a state variable `currentOpen` that keeps track of which index in the array is open and only show that one? – sid c Jul 24 '21 at 00:23

1 Answers1

0

Use a single index variable in state instead, which indicates the current open item. Something along the lines of

const [openIndex, setOpenIndex] = useState(-1); // none open initially
const makeHandleClick = i => () => {
  setOpenIndex(i === openIndex ? -1 : i);
};
// ...
return students.map((student, i) => (
  // ...
   <span onClick={makeHandleClick(i)} className='plus-minus'>
    {openIndex === i ? '\u2795' : '\u2796'}
  }</span>

To check whether a student item should be open or closed when rendering, check if i === openIndex. No need for the icon state variable as well.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • There needs to be a slight modification. The onClick has to be a function, which yours is not. So you need to change it to `onClick = {() => makeHandleClick(i)}` – sid c Jul 24 '21 at 00:25
  • It's a higher-order function so as to pass the `i` into the closure, which makes the syntax a bit easier. (See how `makeHandleClick` returns a function.) Should work as is, I think. – CertainPerformance Jul 24 '21 at 00:26
  • @sidc makeHandleClick will return a function. So it is okay – invisal Jul 24 '21 at 00:26
  • @invisal Yes, correct. I didn't notice that. Perhaps change makeHandleClick to be a regular function, and change the onClick to have an arraow function. – sid c Jul 24 '21 at 00:27
  • 1
    @sidc Why? The entire point of using a curried/higher-order function is to avoid the anonymous handler function. – Drew Reese Jul 24 '21 at 00:43
  • @CertainPerformance worked like a charm thanks. Where can i read more about the syntax for the makeHandleClick function? why doesnt it work as makeHandleClick = (i) => { //some code } – Ben Shekhtman Jul 24 '21 at 01:25
  • @BenShekhtman It's a bit like currying. See https://stackoverflow.com/questions/36314/what-is-currying and https://stackoverflow.com/questions/28889450/when-should-i-use-a-return-statement-in-es6-arrow-functions – CertainPerformance Jul 24 '21 at 01:26
  • @CertainPerformance also how can i account for multiple items open at a time? when i open one another closes? Assuming the user would like to have more than one open at a time does setOpenIndex need to be coverted to an array to accept more than one possible value? – Ben Shekhtman Jul 24 '21 at 01:27