samair ali
samair ali

Reputation: 802

on first button press state is not updating but function called

on first button press onChange method function is called but state is not updating as it should and on second button press it is updating see this

import React,{useState} from 'react';
function MainHeader(props) {
    const [FirstName, setFirstName] = useState('')
    const [User, setUser] = useState({
        FirstName: '',
        LastName: ''
    })
    const nameOnChange = (event) => {
        setFirstName(event.target.value)
        console.log(FirstName)
    }
    const addName = () => {
        setUser({
            ...User,
            FirstName: FirstName
        })
        console.log(User)
        props.addUserToFirebase(User)
    }

    return (
        <div>
            <h1>Checking</h1>
            <input type="text" onChange={(e) => nameOnChange(e)} value={FirstName}  />
            <button onClick={() => addName()}>Enter</button>
        </div>
    );
}

on nameOnChange it is console.log(FirstName) when first time a pressed something then console logs empty state (initial state) and on second button it updates the previous button pressed. I have tried creating class component as well but i am seeing the same issue , same thing happens in the addName function it updates state on second click . see console enter image description here

Upvotes: 1

Views: 491

Answers (2)

WillD
WillD

Reputation: 6512

https://reactjs.org/docs/hooks-effect.html

You must use useEffect().

const nameOnChange = (event) => {
    setFirstName(event.target.value)
}

useEffect(()=>{
    if(FirstName !== ''){
         console.log(FirstName)
    }
}, [FirstName])

const addName = () => {
    setUser({
        ...User,
        FirstName: FirstName
    })
}

useEffect(()=>{
    if(User.FirstName !== '' && User.LastName !== ''){
          console.log(User)
          props.addUserToFirebase(User)
    }
}, [User])

Upvotes: 1

Pushkin
Pushkin

Reputation: 3604

I don't see a problem here. It is working perfectly as it should be. But the only problem I see is your wrong understanding of how React works or how Functional Programming works in general.

There's no mutation in Functional Programming

    const nameOnChange = (event) => {
        // event => new value
        // FirstName => old value
        // they remain that way throughout this function call

        setFirstName(event.target.value)
        // even if you set the state, the values won't change
        // they will be updated only in next function call

        console.log(FirstName) // still old value
    }

The same goes for addName()

For each re-render React call the function MainHeader with values that will not be mutated throughout their call or life. When value are updated, React will call MainHeader with the updated the values.

Correct way of using your Component

Works, but not better way


const addName = () => {
  setUser({
     ...User,
     FirstName: FirstName
   })

   //
   console.log({
     ...User,
     FirstName: FirstName
   }) // new value, since User is not mutated, User will still have the old value
   props.addUserToFirebase(({
     ...User,
     FirstName: FirstName
   })
 }

Better way

Always use useEffects for side effects.

// Just set the state
const addName = () => {
  setUser({
     ...User,
     FirstName: FirstName
   })
}

// handle side effects here

useEffect(() => {
    // check is needed here, since it will be
    // called on component's first mount
    if(User.FirstName !== ''){
          console.log(User)
          props.addUserToFirebase(User)
    }
}, [User])

// This will be called whenever React detects a change in `User`

Upvotes: 2

Related Questions