New to programming:, have built a collapsable accordion in an NextJs app using the react-collapse package. It works as intended, the problem comes with how it is tracking what ‘drawer’ is currently open. I’m trying to, in a sibling have a different image shown per drawer.
currently I iterate through an array of items to generate each section:
{
accordionData.map((item, idx) => {
return (
<AccordionItem
key={idx}
open={idx === open}
title={item.title}
desc={item.desc}
link={item.link}
url={item.url}
toggle={() => toggle(idx)}
/>
)
})
}
I have a useState hook:
const [open, setOpen] = useState(0);
and my toggle function looks like:
const toggle = (idx) => {
if(open === idx) {
return setOpen(null)
}
console.log(idx)
setOpen(idx)
console.log(open)
}
What I want is for example: when the first instance of is open to have an image displayed in a div completely outside of the accordion, and then as the accordion items are opened the image changes.
I assumed I would do this by conditional rendering:
if open == 0 then render imageX else if open == 1 then render imageY …and so on
problem is that open
is never set to the correct index of my array and counterintuitively its also never wrong in a predictable manner so I could write something like if open = (0+1)
as its index is changing every time its opened. As per my console logs above my first one console.log(idx)
is always correct, however the following one console.log(open)
is always wrong.
2
Answers
setOpen
is asynchronous in React. When you callsetOpen
, React doesn’t immediately update the state, so the subsequentconsole.log(open)
won’t reflect the updated state immediately after thesetOpen
call.You can test with this:
But,
open
won’t be immediately updated where you callsetOpen
because state updates are asynchronous. If you need to perform actions based on the updated state, you should use the callback passed tosetOpen
.Now, you can conditionally render your images based on the value of open:
I believe the best approach is to use the useEffect hook.
You’re right. The state doesn’t get updated immediately after the call, but you can react to that change once it happens.
Here is an example of the useEffect hook:
If you only use the toggle function to react to changes in the open state and not in any other case, you can write the entire function directly within the useEffect hook.