Reputation: 1664
I've got the following state:
const [places, setPlaces] = useState(false)
const [selectedPlaces, setSelectedPlaces] = useState([])
I asynchronously populate places by calling an API that returns an array of objects that looks something like:
[
{name: "Shop #1", id: 1},
{name: "Shop #2", id: 2}
]
My goal is to render these objects, and have their ID to be added/removed from the selectedPlaces state.
Render:
return (
<div>
<div>
You have selected {selectedPlaces.length} total places
</div>
(places === false)
? <div>Loading...</div>
: places.map(place => { // render places from the places state when loaded
let [name, id] = [place.name, place.id]
return <div onClick={() => {
setSelectedPlaces(selected => {
selected.push("dummy data to simplify")
return selected
})
}}>{name}</div>
})
</div>
)
I've removed the key and added dummy data to make the movements simpler.
The problem arises when clicking on a div, the "You have selected ... total places" doesn't refresh until I force a re-render using fast refresh or through other methods (using browser/NextJS). Is this correct behaviour? It's as-if the state isn't being changed, but a
console.log
on thesetSelectedPlaces
displays fresh data symbolizing it is being changed.
I've tried:
useEffect
handler for the selectedPlaces
state which would setAmtPlaces
using the length of the selected places. The same issue arises.Upvotes: 0
Views: 429
Reputation: 35261
Add a {}
wrapper for the ternary operator:
{
places === false
? (...)
: (....)
}
push
mutates the state. Use spread or concat
in setSelectedPlaces
setSelectedPlaces(selected =>
selected.concat("abc")
)
let [name, id] = [place.name, place.id]
can be change to let { name, id } = place
Here's a snippet:
const { useState } = React;
function App() {
const [places, setPlaces] = useState([
{ name: "Shop #1", id: 1 },
{ name: "Shop #2", id: 2 }
])
const [selectedPlaces, setSelectedPlaces] = useState([])
const onPlaceClick = id => setSelectedPlaces(state => state.concat(id))
return (
<div>
<div> You have selected {selectedPlaces.length} total places </div>
{ (places === false)
? <div>Loading...</div>
: places.map(({ id, name }) =>
<div onClick={_ => onPlaceClick(id)}>{name}</div>
)
}
<span>{selectedPlaces.join()}</span>
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Upvotes: 2