React useEffect缺少依赖项

时间:2020-07-21 14:55:59

标签: reactjs react-hooks

嗨,我是新来的人,当我将整个函数放在useEffect中时,我会使用pincode设置状态和城市,当它的长度为6位数字时,它会出现错误,包括setPersonalDetState,我也想使用相同的功能来验证我无法将其包含在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>
  );
};

1 个答案:

答案 0 :(得分:0)

您可以将useCallback设为fetchPincode,以便正确地将其指定为效果的依赖项。只要密码更改,它就会运行,但是由于fetchPincode回调没有依赖关系,因此不会触发效果。

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>
  );
};

我已经重写了fetchPincode以使用老式的Promise语法,因为它不得返回任何内容以用作useEffect回调。我回答了类似的问题here

为什么要使用useCallback,以便在重新渲染之间保持相同的功能引用。如果对函数的依赖关系发生更改,则对该函数的引用也会更改(依赖关系在函数之后立即指定为数组,作为useCallback的第二个参数)。

为什么要使用相同的函数引用??因为如果将其作为对另一个挂钩的依赖项(例如useEffect),则更改引用可能会导致效果重新运行(如果出现效果) ,如果该函数引用更改得太频繁,则可能不希望这样做。

在您的特定情况下,只要您键入pincode都会更改(不是100%确定,但是我认为setCredentials是这样做的,我没有看到它的声明)。这将导致对fetchPincode的函数引用发生更改。如果将其指定为对效果的依赖关系,则在函数ref更改时,效果将运行。 但是您还指定了pincode作为依赖项,因此无论如何都会对每个键输入产生影响。但是您可能会考虑在指定的非活动时间(用户未键入)后发出请求为去抖动

要了解钩子: