Mani
Mani

Reputation: 2563

onChange is resetting state - useState

I'm not new to ReactJs but somehow when I console.log in my component function it shows that already set properties are also reset. below is my complete functional component

import React, { useState } from 'react';
import {
  Grid, Typography, Paper, TextField,
} from '@material-ui/core';
import Autocomplete from '@material-ui/lab/Autocomplete';
import SomeComponent from '../../common/SomeComponent';
import countries from '../../utils/countries_data';
import AlertMsg from '../../utils/Alert';
import { MarkRequired } from '../style';

const App = ({ classes, handleNext, handlePay }) => {
  const [contact, setContact] = useState({
    firstName: '',
    lastName: '',
    address1: '',
  });

  const handleChange = (e) => setContact({
    ...contact,
    [e.target.name]: e.target.value,
  });
  console.log('above splitAddressProperties', contact);
  const splitAddressProperties = (data) => {
    console.log('func start', contact);
    const country = countries.filter(
      (count) => count.alpha2 === data.country_code || count.alpha3 === data.country_code,
    );
    setContact({
      ...contact,
      address1: data.address,
      city: data.city,
      zip: data.zip,
      country: country[0],
    });
    console.log('func end', contact);
  };


  return (
    <Grid item xs={12}>
      <Paper className={classes.paper}>
        <Typography className={classes.inputText}>Contact Information</Typography>

        <Grid container style={{ marginBottom: '15px' }}>
          <Grid item xs={6} style={{ paddingRight: '10px' }}>
            <Typography className={classes.inputTitle}>
              First Name
              <MarkRequired>*</MarkRequired>
            </Typography>
            <input
              className={classes.inputsty}
              value={contact.firstName}
              onChange={handleChange}
              type="text"
              name="firstName"
            />
          </Grid>
          <Grid item xs={6} style={{ paddingLeft: '10px' }}>
            <Typography className={classes.inputTitle}>
              Last Name
              <MarkRequired>*</MarkRequired>
            </Typography>
            <input
              className={classes.inputsty}
              value={contact.lastName}
              type="text"
              onChange={handleChange}
              name="lastName"
            />
          </Grid>
        </Grid>
        <Grid style={{ marginBottom: '15px' }}>
          <Typography className={classes.inputTitle}>
            Address
            <MarkRequired>*</MarkRequired>
          </Typography>
          <SomeComponent
            className={classes.inputsty}
            value={contact.address1}
            onChange={splitAddressProperties}
          />
        </Grid>
      
      </Paper>
    </Grid>
  );
};

export default App;

if I enter the first and last name and enter SomeComponent value splitAddressProperties is triggered but it shows that contact's value is as same as default. thing to note is that console.log('above splitAddressProperties', contact); fires two times when first andd last names are entered.

Upvotes: 1

Views: 1063

Answers (1)

Vlad Gincher
Vlad Gincher

Reputation: 1102

I'ts not enough information to really find the problem, but I'm guessing that SomeComponent stores and uses an old reference of the onChange prop.

For example:

const SomeComponent = (props) => {
    // ...
    const innerOnChange = useCallback(
        (data) => {
            props.onChange(data);
        }, 
        // Note that the deps array doesn't have onChange:
        []
    );
    // ...
}

What I would do is access the current contact from the setState:

setContact(currentContact => ({
    ...currentContact,
    address1: data.address,
    city: data.city,
    zip: data.zip,
    country: country[0],
}));

setContact's reference will never change and it will always give you the current contact object. (But it's better to fix SomeComponent)

Upvotes: 3

Related Questions