简体   繁体   中英

Unable to update initial state in real time using useState

First of all I apolizize if I am not able to explain the issue properly. I am also aware that useState is asynchronous. I have tried to simply the code as much as possible. So bascially, in the code below I have a method handleSubCatChange,that runs on onChange event. Whenever a checkbox is seleted the subs:[] in the initial state needs to be populated by the value from the checkbox. The handleSubCatChange methods checks if the elements of subarray are already in selectedValues.

I have three console.logs, if I click all the three checkboxes one by one the last one console.log('0002'), shows that the selectedValues array is updated rightaway.

The console.log('000'), displays empty selectedValues state on the first click and on clicking the second checkbox, logs the first checkbox values, that is apple and when the third check box is clicked the second check box value which is banana is logged. The third console.log('0001') is even slower, only after all the checkboxes are clicked it displays the first one that is apple in it's array. I have also tried to use the JSON.stringify, the results are slightly different. {JSON.stringify(selectedValues)}, udpates in real time but {JSON.stringify(values.subs)} only displays first two elements apple and banana when all three checkboxes have been clicked.

I have lot more properties in my initialstate but for simplicity I have only mentioned title and subs. The check boxes are part of a form element so I need to update the subs:[] in real time so that II can submit the form with other values. I have tried useEffect but no luck. Please help.

import React,{useState} from 'react';

const initialState={ title:'glasses', subs:[],    }

const subarray=['apple','banana','orange']

const ProductCreate=()=>{

const [values,setValues]=useState(initialState); const[selectedValues,setSelectedValues]=useState([]);

useEffect(()=>{
    },[selectedValues])

const handleSubCatChange=(checkedName)=>{

if(selectedValues.includes(checkedName)){
    setSelectedValues(selectedValues.filter((c)=> c!=(checkedName)))
}
  else{ 
    setSelectedValues([...selectedValues,checkedName])
}
    setValues({...values,subs:selectedValues}) 
console.log('0000',selectedValues); console.log('0001',values.subs);}     
    )}
return( <>
 
{JSON.stringify(values.subs)}
{JSON.stringify(selectedValues)}


{subarray.map((s)=>
 <div key={index} >
  {console.log('0002',selectedValues)}
     <input type="checkbox" 
     value={s} 
     onChange={()=>handleSubCatChange(s)}
     />
 </div>
}
</>     )
}

If you want values state to be synchronized with selectedValues state, then use useEffect hook properly.

Use handleSubCatChange function only to change state of selectedValues .

const handleSubCatChange = (checkedName) => {
    if (selectedValues.includes(checkedName)) {
      setSelectedValues(selectedValues.filter((c) => c !== checkedName));
    } else {
      setSelectedValues([...selectedValues, checkedName]);
    }
  };

And use useEffect hook to change the values state only when selectedValues state is changed.

useEffect(() => {
    setValues({ ...values, subs: selectedValues });
    console.log("0000", selectedValues);
    console.log("0001", values.subs);
  }, [selectedValues]);

Working demo at CodeSandbox .

Edit:

To add initial values during selectedValues initialization. Change as:

const [selectedValues, setSelectedValues] = useState(['banana']);

Add checked into input to preselect checkboxes.

checked={selectedValues.includes(s)}

Look at the demo carefully.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM