0

I've read dozens of pages on React State hooks including:

We dont know how React state hook work

LifeCycleDiagram

Why calling react setState method doesn't mutate the state immediately?

I can't figure out how to, run SetState(xxxx) then use the new State data to determine the next set of data I need to load during the initial page data load.

After trying with multiple useEffects with it's own defined dependency array argument, in an attempt to force an immediate rerender so that the state data will be updated, it still doesn't work.

Fails because formDetails.roleIdSelected, and the whole formDetails state is still at initial state.

Sample Code:

function PersonForm(props){

const [departmentList, setDeparmentList] = useState([]);
const [departmentIdSelected, setDepartmentIdSelected] = useState(1);
const [roleList, setRoleList] = useState([]);
const {idPerson} = useParams();
const [roleIdSelected, setRoleIdSelected] = useState("");

const [formDetails, setFormDetails] = useState({ //initial values
        firstName: "",
        lastName :"",
        departmentIdSelected: "",
        roleIdSelected : "",
    })

useEffect(()=>{ //Grab list of departments from API on DidMount
        setDeparmentList(getAllDepartments());
    },[])

useEffect(()=>{ //Grab the specific person data when the idPerson state is updated (DidUpdate)
    getRunPerson(idPerson);
},[idPerson])

useEffect(()=>{ //Find the Role Entity by the roleID of the person, once a change in formDetails state is detected (DidUpdate)
    if(idPerson !== "new"){ 
        const roleEntity = getRole(formDetails.roleIdSelected);
        setDepartmentIdSelected(roleEntity.DepartmentId); //FAIL because formDetails is actually stale
    }
},[formDetails])
    
const getRunPerson =   (id) =>{
    const person =   getPerson(id);
    setFormDetails({
        
        firstName:person.fname,
        lastName : person.lname,
        roleIdSelected : person.roleId,  
        
    });
    setRoleIdSelected(person.roleId);
}
......
return(
        <React.Fragment>
            <div className="table table-dark">
                <TextField placeHolder = "Type Here" label = "First Name" statekey={Object.keys(formDetails)[0]} onChangeText={handleValueChange} value ={formDetails.firstName} />
                <TextField placeHolder = "Type Here" label = "Last Name" statekey={Object.keys(formDetails)[1]} onChangeText={handleValueChange} value = {formDetails.lastName}/>
                {console.log("formDetails.departmentIdSelected: ", formDetails.departmentIdSelected)}
                <SelectField label = "Department" statekey={Object.keys(formDetails)[2]} options={departmentList} onChange = {handleValueChange} value = {departmentIdSelected}/>
               
                

            </div>
        </React.Fragment>)
}
klau
  • 67
  • 1
  • 9
  • Are these really synchronous functions to get the data? – Bergi Nov 28 '21 at 06:55
  • Why do you have two different states for `roleIdSelected`? That `getRunPerson()` has to set two states might as well be the cause of your problem. – Bergi Nov 28 '21 at 06:59
  • Your third effect only lists `[formDetails]` as its dependencies but actually also depends on the value of `idPerson`. – Bergi Nov 28 '21 at 07:00
  • Currently Yes, it's a fake test service that's actually just an imported synchronous function within the same solution, eventually it'll be using a webapi json backend via axios calls – klau Nov 28 '21 at 07:01
  • Add a `setTimeout` to your fake mocks then, asynchronous code will behave very differently. – Bergi Nov 28 '21 at 07:02
  • @Bergi yes, that was added only to test if having roleIdSelected as it's own state would help useEffect detect the change (I added it to the dependency), but it did not – klau Nov 28 '21 at 07:05
  • @Bergi even with the idPerson added to the dependency array, the formDetail data remains stale – klau Nov 28 '21 at 07:11
  • Of course, I can cheat and do both setState and also return the data from the mock directly to the next line that needs it as the parameter. But this seems wrong in principle – klau Nov 28 '21 at 07:14
  • There's no cheating involved in that - if you want to do multiple things in one effect, and do multiple intermediate `setState`s in between them, that's a totally fine approach. – Bergi Nov 28 '21 at 18:20

0 Answers0