-1

I am changing state after calling an onChange event it is not reflecting immediately. How can I make my state change Immediately. Here is my parent component code.

import React from 'react';
import {One, test, test1} from './Sample/SampleData';

export const FirstUser = () => {
    const [data, setData] = React.useState(One)
    const [id, setId] = React.useState("")
    
    React.useEffect(()=> {
            onChangeId(id)
    },[id])

const onChangeId = (myId:string) => {
    setId(myId)
    switch (myId) {
        case '1':
            setData(test);
            break;
        case '2':
            setData(test1);
            break;
        default:
            setData(One);
            break;
    }
}
    return (
        <div>
            <ChildComponent
                firstData={One} 
                onChangeId={onChangeId} 
                secondData={data}
            />
        </div>
    );
};

And below is my ChildComponent code -

import React from 'react';

export const ChildComponent = ({
    firstData,
    onChangeId,
    secondData
}: NewInterface) => {
const [format, setFormat] = useState(secondData);
const onChange = (
        type: string,
        val:string
    ) => {
        
        if (type === "welcome") {
                onChangeId(val);
                setFormat(secondData);                
                console.log(secondData , "secondData")                
        }
    };
    return (
        
            <React.Fragment>                
                <AnotherChildComponent
                    onChange={onChange}
                    firstData={firstData}
                    newData={format}
                />
            </React.Fragment>
    
    );
}

code for AnotherChildComponent is -

import React from 'react';

export interface SomeInterface {
    onChange: (
        type: string,
        val:  string
    ) => void;
    
    firstData: DataInterface,
    newData: DataInterface
}

export const AnotherChildComponent = ({
    onChange,
    firstData,
    newData
}: SomeInterface) => {
    let { oneData, twoData } = firstData;
    let { thirdData } = newData;

    const translatedOneData = oneData.map(({ label, value }) => ({
        label: translateFn!(label),
        value
    }));

    const translatedTwoData = twoData.map(({ label, value }) => ({
        label: translateFn!(label),
        value
    }));

    const translatedThreeData = thirdData.map(({ label, value }) => ({
        label: translateFn!(label),
        value
    }));
console.log(newData, "newData")
    return (
        <React.Fragment>
                
                    <Grid container>
                        <Select
                            options={translatedTwoData}
                            value={selectedTwoData}                         
                            onChange={(val: string) =>
                                onChange('welcome', val)
                            }
                        />
                        <SectionLabel label="Newdata" />
                        <Select
                            options={translatedThreeData}
                            value={selectThirdData}
                            onChange={(val: string) =>
                                onChange('guest', val)
                            }
                        />
                    </Grid>
                
            
        </React.Fragment>
    );
};

After setting state of setFormat, When I am consoling secondData in ChildComponent then it is displaying data on second time change. It is not displaying data in first time change(immediately). Means I am getting desired secondData when I call onChangeId two times. It is not showing immediately. I have used useEffect and passed id & data one by one but still changes data on two times call. So can anyone help me in that?

Anurag Mishra
  • 647
  • 3
  • 15
  • 31
  • `React.useEffect(()=> { onChangeId(id) },[id])`. this is not a good practice since you added id as a dependency and inside useEffect, you are updating the id. – wangdev87 Nov 20 '20 at 17:39
  • @WilliamWang So how can I do this to achieve my desired result, Can you help me a bit ? – Anurag Mishra Nov 20 '20 at 17:42
  • Does this answer your question? [useState set method not reflecting change immediately](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) – Brian Thompson Nov 20 '20 at 17:49
  • @BrianThompson I have already gone through it, but in my case it's not working. – Anurag Mishra Nov 20 '20 at 17:50
  • If you followed the answer in that question then you would not expect the code you provided to work. Its just not how React or Javascript work. – Brian Thompson Nov 20 '20 at 17:52
  • Here's [another explanation](https://stackoverflow.com/questions/64899105/understanding-weird-setstate-behaviour-in-reactjs-using-usestate-hooks/64900092#64900092). – Brian Thompson Nov 20 '20 at 17:53

1 Answers1

0

You should first know that useState mutate callbacks are asynchronous, so your console.log(...) right after calling the callback will always show the old value. However, I'm pretty sure the UI updates are working fine, unless you show us the code to AnotherChildComponent.

Either way, your console.log will always output the same value as mount time since that is when it was defined.

And a WARNING, if you are not careful with the way you call onChangeId in your parent component, you might end up with a recursion.

Dev Yego
  • 539
  • 2
  • 12