0

Hi there i'm new to react i'm setting state and city using pincode when it has length of 6 digits when i put whole function inside useEffect it gives error to include setPersonalDetState & i also want to use same funtion to validate i cannot include it inside useEffect

const intialState = {
  city: '',
  state: '',
  pincode: ''
};

const PersonalDetails = () => {
  const [personalDetState, setPersonalDetState] = useState(intialState);

  const { city, state, pincode } = personalDetState;

  const fetchPincode = async (pincode) => {
    if (pincode.length != 6) {
      return;
    }
    let cityState = await axios.get(
      `https://api.postalpincode.in/pincode/${pincode}`
    );
    const { Status, PostOffice } = cityState.data[0];

    const { District, State } = PostOffice[0];
    personalDetState['city'] = District;
    personalDetState['state'] = State;
    return setPersonalDetState({ ...personalDetState });
  };
  
  useEffect(() => {
    fetchPincode(pincode);
  }, [pincode]);

  const handleChange = (event) => {
    let { value, name } = event.target;
    
    if (name === 'pincode') value = value.replace(/\D/g, '');
    if (name === 'pincode' && value.length === 7) return;

    setPersonalDetState({ ...personalDetState, [name]: value });
  };

  return (
    <Fragment>
      <input
        type='text'
        name='pincode'
        value={pincode}
        onChange={handleChange}
      />
      <input type='text' name='city' value={city} disabled />
      <input type='text' name='state' value={state} disabled />
    </Fragment>
  );
};
Siddhesh Nayak
  • 95
  • 4
  • 11

1 Answers1

0

You can useCallback for fetchPincode in order to correctly specify it as a dependency to the effect. It will run whenever pincode changes, but since fetchPincode callback doesn't have dependencies, it won't trigger the effect.

const intialState = {
  city: '',
  state: '',
  pincode: ''
};

const PersonalDetails = () => {
  const [personalDetState, setPersonalDetState] = useState(intialState);

  const { city, state, pincode } = personalDetState;

  const fetchPincode = useCallback(() => {
    if (pincode.length != 6) {
      return;
    }
    
    axios.get(
      `https://api.postalpincode.in/pincode/${pincode}`
    ).then(cityState => {
        const { Status, PostOffice } = cityState.data[0];

        const { District, State } = PostOffice[0];
        setPersonalDetState(prev => ({
           city: District,
           state: State
        }));
    });
  }, [pincode]);
  
  useEffect(fetchPincode, [pincode]);

  const handleChange = (event) => {
    let { value, name } = event.target;
    
    if (name === 'pincode') value = value.replace(/\D/g, '');
    if (name === 'pincode' && value.length === 7) return;

    setCredentials({ ...userCredentials, [name]: value });
  };

  return (
    <Fragment>
      <input
        type='text'
        name='pincode'
        value={pincode}
        onChange={handleChange}
      />
      <input type='text' name='city' value={city} disabled />
      <input type='text' name='state' value={state} disabled />
    </Fragment>
  );
};

I've rewritten the fetchPincode to use the old-fashion Promise syntax, because it must not return anything in order to be used as useEffect callback. I answered a similar question here.

Why useCallback? In order to keep the same function reference between re-renders. Reference to the function will change if its dependencies change (dependencies are specified as array right after the function, as second parameter to useCallback).

Why the same function reference? Because if included as a dependency to another hook (say useEffect), changing reference may cause the effect to re-run (in case of effects), which is probably not desired if that function reference changes too often.

In your particular case, pincode will change whenever you type (not 100% sure, but I assume setCredentials is doing that, I didn't see its declaration). This will cause the function reference to fetchPincode to change. If specified as a dependency to an effect, the effect would run if the function ref changes. But you also have pincode specified as dependency so effect would run on each key input anyway. But you might think about making the request after specified period of inactivity (user not typing), also known as debounce.

To learn about hooks:

Rosen Dimov
  • 1,055
  • 12
  • 32
  • i'm getting React Hook useCallback has a missing dependency: 'personalDetState' – Siddhesh Nayak Jul 21 '20 at 15:47
  • I've updated my answer to use the version of ```setPersonalDetState``` with function taking previous state. That way you no longer need ```personalDetState``` as a dependency. – Rosen Dimov Jul 21 '20 at 16:00
  • ok i got it. i have to spread all prev state thanks man, can u explain what is missing dependency when and what to use, how can i get to know in short or any source i can't get it in react documentation – Siddhesh Nayak Jul 22 '20 at 06:46
  • I updated my answer, let me know if it's clear enough. ;) – Rosen Dimov Jul 22 '20 at 08:12