React useEffect called within loop - only the final effect is fired

Viewed 39

My app has a list of checkboxes along with a select/deselect all at the top. I store the currently selected checkboxes in a state array and when a checkbox is set a useEffect() is fired to drop some markers on a leaflet map. The select all will attempt to loop through the rows and set each checkbox to true which should subsequently fire the useEffect for each row.

enter image description here

At a high level the code is doing this:

const [checkboxStatus, setCheckboxStatus ] = useState([]);
const [currentRow, setCurrentrow] = useState(null);


 useEffect(() => { 
     addMarkersToMap(currentRow)

 }, [checkboxStatus]);

const handleCheckboxClick = (event, row) => {
     setCurrentrow(row);  
     setCheckboxStatus(newSelected);
  
 }

 const handleSelectAllClick = (event) => {
      props.rows.map((n) => {
         setCurrentrow(n)
         var chk = props.window.tablename + '_' + n.id + "_chk"
         setCheckboxStatus(prevArray => [...prevArray, chk])
        })
 }

The single checkbox click works as expected - the checkboxStatus is updated and the useEffect fires to add my map markers for the current row. However the selectAll will only fire the useEffect for the final item in the list. I assume this has to do with some sort of asynchronous behavior and I probably am fundamentally doing it wrong :) Any insight is most appreciated.

Thanks

2 Answers

In your code currentRow is always going to be the last.

In the checkboxesStatus case, why not use the map function like this?

 const handleSelectAllClick = (event) => {
      var checkboxStatus = props.rows.map((n) => {
         return props.window.tablename + '_' + n.id + "_chk"
        })
      setCheckboxStatus(checkboxStatus)
 } 

useEffect is a react hook, and it will be scheduled for running whenever its dependencies are modified (on our case checkboxStatus).

The problem is that when we trigger a few such events (checkbox clicks) they may be batched by react and modified all at once, which means that you won't get useEffect to run separately for each one of them.

On such cases (more complex scenarios) when we want to "catch" multiple changes and handle them together - we should consider using useReducer.

Related