React hooks state not using latest

setTags changes the internal react state and doesn't change the value of tags directly. So it doesn't get updated till the next render.

Use this call instead:

setTags(currentTags => ({...currentTags, all}));

And do the same with available.


In the react docs, you can see how useEffect works (https://reactjs.org/docs/hooks-effect.html)

Experienced JavaScript developers might notice that the function passed to useEffect is going to be different on every render. This is intentional. In fact, this is what lets us read the count value from inside the effect without worrying about it getting stale. Every time we re-render, we schedule a different effect, replacing the previous one. In a way, this makes the effects behave more like a part of the render result — each effect “belongs” to a particular render. We will see more clearly why this is useful later on this page.

What this means, is that each side effect within your render function will only have access to the initial result of useState. Remember that react states are immutable, so it doesn't make sense for you to update the state, and then try and use the updated version within the same render cycle.

You can see this by simply calling:

setTags({ all: ['test'] })
console.log(tags)

You should notice that tags does not change at all.

Personally I would use hook conventions here, and separate your useState out into two separate variables:

const [allTags, setAllTags] = useState([])
const [availableTags, setAvailableTags] = useState([])

This makes your effects more explicit (as they only need to update the one variable), and improves readability.