简体   繁体   中英

React: Child component doesn't get updated values when reset function is triggered in parent component

Update:

I think the problem is that Child 2 components are not rerendering because there are the same props when handleReset() is triggered in parent component.. but how can I make them rerendering? I tried with useEffect but nothing happens.

I'm struggling for several hours with the following issue: I have a parent component in which I have some values passed from useState to child 1 (CustomerData) then to child 2 (-AddressForm and -CustomerForm).

My problem is that when the handleReset() from parent component is triggered, the values from child2 (AddressForm and CustomerForm) are not updated and I don't understand why. I Think that Child 2 components are not rerendering when I reset the values and somehow I need to pass in some other way the stated in the set hook from handleReset().

If somebody can help me solve this issue please. Here are my components:

Parent component:


function WidgetCustomerData(props): JSX.Element {
    const customerDataTest = {
        customerFirstName: 'firstNameTest',
        customerLastName: 'lastNameTest',
        customerPhone: '1313212',
        customerEmail: 'test@test.com',
        customerAddress: 'Musterstraße',
        customerAddressNo: '12',
        customerZip: '80335',
        customerCity: 'Berlin',
        deviceAddress: 'Straße',
        deviceAddressNo: '152',
        deviceZip: '32214',
        deviceCity: 'Hamburg',
    };

  const [customerData, setCustomerData] = useState({
    addressValue: customerDataTest.customerAddress,
    addressValueNr: customerDataTest.customerAddressNo,
    addressValueZip: customerDataTest.customerZip,
    addressValueCity: customerDataTest.customerCity,
    customerFirstName: customerDataTest.customerFirstName,
    customerLastName: customerDataTest.customerLastName,
    customerPhone: customerDataTest.customerPhone,
    customerEmail: customerDataTest.customerEmail,
    deviceAddress: customerDataTest.deviceAddress,
    deviceAddressNo: customerDataTest.deviceAddressNo,
    deviceZip: customerDataTest.deviceZip,
    deviceCity: customerDataTest.deviceCity
  })

  const handleClose = () => {
    props.handleClose();
}

    const handleSubmit = async (e) => {
        e && e.preventDefault();
        const formUrl = 'https://fetch.mock/widget-customer-data/addCustomerData';
        const formData = new FormData(e.target);
        for (const [name, value] of formData) {
            console.log(`${name}: ${value}`);
        }

        const response = await fetch(formUrl.toString(), {
            method: 'POST',
            body: formData,
            credentials: 'same-origin',
        });

        const data = await response.json();
    };

    const handleReset = () => {
        console.log('handleReset ----');
        
      setCustomerData({
      addressValue: customerDataTest.customerAddress,
      addressValueNr: customerDataTest.customerAddressNo,
      addressValueZip: customerDataTest.customerZip,
      addressValueCity: customerDataTest.customerCity,
      customerFirstName: customerDataTest.customerFirstName,
      customerLastName: customerDataTest.customerLastName,
      customerPhone: customerDataTest.customerPhone,
      customerEmail: customerDataTest.customerEmail,
      deviceAddress: customerDataTest.deviceAddress,
      deviceAddressNo: customerDataTest.deviceAddressNo,
      deviceZip: customerDataTest.deviceZip,
      deviceCity: customerDataTest.deviceCity
    })
    };

    return (
        <div className="customer-data">
            <Dialog
                onClose={handleClose}
        open={props.open}
                aria-labelledby="customized-dialog-title"
                PaperProps={{
                    style: { borderRadius: 20, minWidth: '80%', maxHeight: 'fit-content' },
                }}>
                <DialogTitle id="customized-dialog-title" onClose={handleClose} />
                <Typography style={{ marginTop: 20, paddingLeft: 48, fontSize: 32, fontWeight: 600 }}>Kundendaten bearbeiten</Typography>
                {/* <DialogContent> */}
                    <form onSubmit={handleSubmit}>
            <div style={{ paddingLeft: 48, paddingRight:48 }}>
              <CustomerData
                customerData={customerData}
              />
            </div>
                        <DialogActions>
                            <ResetButton onClick={handleReset} variant="contained" color="primary">
                                Reset
                            </ResetButton>
                            <SaveButton type="submit" variant="contained" color="primary">
                                Save
                            </SaveButton>
                        </DialogActions>
                    </form>
                {/* </DialogContent> */}
            </Dialog>
        </div>
    );
}
export default WidgetCustomerData;

Child1


export default ({nextStepAction, customerData }: MoleculeSystemManagementCustomerDataProps): JSX.Element => {

  return (
    <div className='c-data'>
      <CustomerForm customerData={customerData} />
      <AddressForm formId='customer' customerData={customerData} />
    </div>
  );
}

Child2


function AddressForm({formId customerData }): JSX.Element {

  const classes = useStyles();

  const { addressValue, addressValueNr, addressValueZip, addressValueCity, deviceAddress, deviceAddressNo, deviceZip, deviceCity } =  customerData; 


  return (
    <Grid container className={classes.borderedRow}>
      <Grid item xs={12} sm={6} md={3} className={classes.formColumn}>
        <div>        
        <InputField type='label' id='address' name={`${formId}-address`} value={formId === 'customer' ? addressValue : deviceAddress} label={'Street'} />
        </div>
      </Grid>

      <Grid item xs={12} sm={6} md={3} className={classes.formColumn}>        
        <InputField type='label' id='city' name={`${formId}-city`} value={formId === 'customer' ? addressValueNr : deviceAddressNo} label={'Number'} />
      </Grid>

      <Grid item xs={12} sm={6} md={3} className={classes.formColumn}>        
        <InputField type='label' id='state' name={`${formId}-state`} value={formId === 'customer' ? addressValueZip : deviceZip} label={'ZIP'} />
      </Grid>

      <Grid item xs={12} sm={6} md={3} className={classes.formColumn}>        
        <InputField type='label' id='zip' name={`${formId}-zip`} value={formId === 'customer' ? addressValueCity : deviceCity} label={'ORT'} />
      </Grid>
    </Grid>
  );
}
export default AddressForm;

I think the problem is occurring because the state is only being passed to the first child component.

If you look carefully, you'll see that during the passage from the child (1) to child(2) there's no state dealing with it. React is not going to update the value of your props if it's not a state.

Probably, you just need to create a state within the first child. Look the example:

Child 1

export default ({nextStepAction, customerData }: MoleculeSystemManagementCustomerDataProps): JSX.Element => {
      const [addressIsDifferent, setAddressIsDifferent] = useState(true);
      const [customerDataState, setCustomerDataState] = useState(customerData)
    
      return (
        <div className='c-data'>
          <CustomerForm customerData={customerData} />
          <AddressForm formId='customer' customerData={customerDataState} />
        </div>
      );
    }

Extra tips: I don't what are the use cases of your project, but I highly recommend you to take a look at React Context API

It's a great idea to use it if you need to pass data through components that need the same data and do cohesive functions.

In a typical React application, data is passed top-down (parent to child) via props, but such usage can be cumbersome for certain types of props (eg locale preference, UI theme) that are required by many components within an application. Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree.

it looks like you are setting the state to the same data as it was initialised. you initialise it with customerDataTest and then set it to customerDataTest . same thing

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM