Home > Mobile >  Unable to update the `setState` inside `useEffect` conditionally
Unable to update the `setState` inside `useEffect` conditionally

Time:09-04

Component For Either Creating Or Editing The User

A part of the code below where I am setting the isActive state conditionally inside useEffect

I am getting the other fields of user_data and successfully updating the state but only setIsActive is not updating the state

function CreateUser() {

    const [isActive, setIsActive] = useState<boolean | undefined>();
    
    useEffect(() => {
        if (params_user_id?.id != null) {
            const SINGLE_USER_URL = `users/${params_user_id.id}/edit`;
            const getSingleUser = async () => {
                const {data} = await axios.get(SINGLE_USER_URL)
                console.log(data)
                setIsActive(data.isactive)
                console.log('isactive', isActive)
            }
            getSingleUser();
        }
    }, [params_user_id])

    return (
        <>
     <Form.Check
          defaultChecked={isActive}
          className='mb-3'
          type='checkbox'
          id='active'
          onChange={e => setIsActive(!(isActive))}
          label='Active: Unselect for deleting accounts.'/> 
        </>
    )

}

Form.Check From Bootstrap-React

When I hit the Edit page

Screen Shot of result page

I did try many things like ternary operator etc checkBox is not checked bcoz it's undefined

CodePudding user response:

Setting the state in React acts like an async function.
Meaning that the when you set the state and put a console.log right after it, it will likely run before the state has actually finished updating.

Which is why we have useEffect, a built-in React hook that activates a callback when one of it's dependencies have changed.

In your case you're already using useEffect to update the state, but if you want to act upon that state change, or simply to log it's value, then you can use another separate useEffect for that purpose.

Example:

useEffect(() => {
   console.log(isActive)
   // Whatever else we want to do after the state has been updated.
}, [isActive])

This console.log will run only after the state has finished changing and a render has occurred.

  • Note: "isActive" in the example is interchangeable with whatever other state piece you're dealing with.

Check the documentation for more info about this.


Additional comments:

  • Best to avoid using the loose != to check for equality/inequality and opt for strict inequality check instead, i.e. - !==
    Loose inequality is seldom used, if ever, and could be a source for potential bugs.

  • Perhaps it would better to avoid typing this as boolean | undefined.
    Unless justified, this sounds like another potential source for bugs.
    I would suggest relying on just boolean instead.

CodePudding user response:

First, you can't get the state's updated value immediately after setting it because State Updates May Be Asynchronous

useEffect(() => {
        if (params_user_id?.id != null) {
            const SINGLE_USER_URL = `users/${params_user_id.id}/edit`;
            const getSingleUser = async () => {
                const {data} = await axios.get(SINGLE_USER_URL)
                console.log(data)
                setIsActive(data.isactive)
                console.log('isactive', isActive) // <-- You can't get updated value immediately
            }
            getSingleUser();
        }
}, [params_user_id])

Change the type of useState to boolean only and set the default value to false.

const [isActive, setIsActive] = useState<boolean>(false);

Then, in Form.Check, update onChange to this:

 <Form.Check
      defaultChecked={isActive}
      className='mb-3'
      type='checkbox'
      id='active'
      onChange={() => setIsActive((preVal) => !preVal)}
      label='Active: Unselect for deleting accounts.'
  /> 
  • Related