最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React child component state is lost after parent component re-renders - Stack Overflow

programmeradmin1浏览0评论

I am using a React hook for parent/child ponent.

Now I have state in my parent ponent (panyIcon), which I need to update based on some validation in the child ponent. I pass validationCallback as a callback function to the child ponent and update my parent state based on the value I get from the child.

Now the issue is after I update the parent state, the state value in my child ponent gets reset. What I am doing wrong in the below implementation ?

function ParentComp(props) {
    const [panyIcon, setCompanyIcon] = useState({ name: "icon", value: '' });

    const validationCallback = useCallback((tabId, hasError) => {
        if (hasError) {
            setCompanyIcon(prevItem => ({ ...prevItem, value: 'error'}));
// AFTER ABOVE LINE IS EXECUTED, my Child ponent state "myAddress" is lost i.e. it seems to reset back to empty value.
        }
    }, []);
    

    const MyChildCmp = (props) => { 
        const [myAddress, setmyAddress] = useState('');

        useEffect(() => {
                if (myAddressExceptions.length > 0) {
                    props.validationCallback('MyInfo', true);
                } else {
                    props.validationCallback('MyInfo', false);
                }
            }, [myAddressExceptions])

    
        const handlemyAddressChange = (event) => {        
            //setmyAddress(event.target.value);
            //setmyAddressExceptions(event.target.value);
            console.log(myAddressExceptions);
        }

        return (
            <>
                <div className="row" style={{ display: 'flex', flexDirection: 'row', width: '1000px'}}>
                        <div style={{ width: '20%'}}>
                            <FormField 
                                label='Company Address' 
                                required
                                helperText={mergedErrorMessages(myAddressExceptions)}
                                validationState={
                                    myAddressExceptions[0] ? myAddressExceptions[0].type : ''
                                }
                            >
                                <Input id='myAddress'
                                    value={myAddress}
                                    //onChange={handlemyAddressChange}
                                    onChange={({ target: { value } }) => {
                                        validateInputValue(value);
                                    }}
                                    onBlur={handleBlur}
                                    inputProps={{maxLength: 9}} />
                            </FormField>
                        </div>
                </div>
            </>
        ); 
    }

    return (
        <div className="mainBlock">
            Parent : {panyIcon}
            {displayMyChild && <MyChildCmp validationCallback={validationCallback}/>}
        </div>
    )
}

export default withRouter(ParentComp);

I am using a React hook for parent/child ponent.

Now I have state in my parent ponent (panyIcon), which I need to update based on some validation in the child ponent. I pass validationCallback as a callback function to the child ponent and update my parent state based on the value I get from the child.

Now the issue is after I update the parent state, the state value in my child ponent gets reset. What I am doing wrong in the below implementation ?

function ParentComp(props) {
    const [panyIcon, setCompanyIcon] = useState({ name: "icon", value: '' });

    const validationCallback = useCallback((tabId, hasError) => {
        if (hasError) {
            setCompanyIcon(prevItem => ({ ...prevItem, value: 'error'}));
// AFTER ABOVE LINE IS EXECUTED, my Child ponent state "myAddress" is lost i.e. it seems to reset back to empty value.
        }
    }, []);
    

    const MyChildCmp = (props) => { 
        const [myAddress, setmyAddress] = useState('');

        useEffect(() => {
                if (myAddressExceptions.length > 0) {
                    props.validationCallback('MyInfo', true);
                } else {
                    props.validationCallback('MyInfo', false);
                }
            }, [myAddressExceptions])

    
        const handlemyAddressChange = (event) => {        
            //setmyAddress(event.target.value);
            //setmyAddressExceptions(event.target.value);
            console.log(myAddressExceptions);
        }

        return (
            <>
                <div className="row" style={{ display: 'flex', flexDirection: 'row', width: '1000px'}}>
                        <div style={{ width: '20%'}}>
                            <FormField 
                                label='Company Address' 
                                required
                                helperText={mergedErrorMessages(myAddressExceptions)}
                                validationState={
                                    myAddressExceptions[0] ? myAddressExceptions[0].type : ''
                                }
                            >
                                <Input id='myAddress'
                                    value={myAddress}
                                    //onChange={handlemyAddressChange}
                                    onChange={({ target: { value } }) => {
                                        validateInputValue(value);
                                    }}
                                    onBlur={handleBlur}
                                    inputProps={{maxLength: 9}} />
                            </FormField>
                        </div>
                </div>
            </>
        ); 
    }

    return (
        <div className="mainBlock">
            Parent : {panyIcon}
            {displayMyChild && <MyChildCmp validationCallback={validationCallback}/>}
        </div>
    )
}

export default withRouter(ParentComp);
Share Improve this question edited Jul 14, 2022 at 23:45 halfer 20.4k19 gold badges109 silver badges202 bronze badges asked Jul 10, 2022 at 15:28 copenndthagencopenndthagen 50.9k105 gold badges313 silver badges492 bronze badges 1
  • 2 Never define a child ponent inside a parent ponent. – Bergi Commented Jul 10, 2022 at 15:31
Add a ment  | 

1 Answer 1

Reset to default 7

Here are some reasons why you can lose state in child (there could be more, but these apply to you most):

    {displayMyChild && <MyChildCmp validationCallback={validationCallback}/>}

Here if at one point displayMyChild is truthy, then made falsy, this means the ponent MyChildCmp will get unmounted, hence all its state will be gone.

But now, even if you didn't have that condition and rendered the MyChildCmp always you would still run into similar problem, this is because you defined MyChildCmp inside another ponent. When you do that, on each render of the parent ponent, the function MyChildCmp is recreated, and the reconciliation algorithm of react thinks you rendered a different ponent type on next render, so it will destroy the ponent instance. Move definition of that ponent outside the parent ponent.

发布评论

评论列表(0)

  1. 暂无评论