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
1 Answer
Reset to default 7Here 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.