useCallBack реагирует на хуки / исчерпывающее предупреждение

Это часть моего кода в React js:

export default function Registration() {
    const [email, setEmail] = useState(null);
    const [password, setPassword] = useState(null);
    const [passwordRepeat, setPasswordRepeat] = useState(null);
    const [isFieldsOK, setFieldsOK] = useState(false);

    useEffect(() => {
        if (checkFieldsOK()) {
            setFieldsOK(true);
        } else {
            setFieldsOK(false);
        }
    }, [checkFieldsOK])

    const checkFieldsOK = () => {
        return (isEmail(email) && isValidPassword(password) && passwordRepeat === password);
    }
}

У меня есть состояние isFieldsOK, которое сообщает мне, действительны ли мои поля, и я хочу, чтобы оно прослушивало каждое изменение в функции регистрации. После запуска я получаю следующее предупреждение:

The 'checkFieldsOK' function makes the dependencies of useEffect Hook (at line 34) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of 'checkFieldsOK' in its own useCallback() Hook  react-hooks/exhaustive-deps

Что именно не так с моим кодом? Что мне следует изменить и почему? Спасибо!


person Naor Anhaisy    schedule 10.01.2021    source источник
comment
Если вы используете eslint, проверьте эту ссылку. stackoverflow.com/questions/59611822/   -  person A Webb    schedule 10.01.2021


Ответы (2)


Поскольку вы не обернули checkFieldsOK в useCallback, он не запомнен, что означает, что он воссоздается при каждом рендеринге. И поскольку ваш useEffect имеет checkFieldsOK в качестве зависимости, этот эффект также будет запускаться при каждом рендеринге.

Точно так же, как говорится в сообщении об ошибке, первый (и я считаю неправильным) вариант - переместить объявление функции внутри useEffect следующим образом:

useEffect(() => {
    const checkFieldsOK = () => {
        return (isEmail(email) && isValidPassword(password) && passwordRepeat === password);
    }

    if (checkFieldsOK()) {
        setFieldsOK(true);
    } else {
        setFieldsOK(false);
    }
}, []);

Но это означает, что он будет работать только при монтировании (поскольку массив зависимостей пуст), поэтому лучший подход - обернуть функцию checkFieldsOK в useCallback, чтобы она не переделывалась при каждом повторном рендеринге, а эффект запускался только тогда, когда поле значения меняются:

const checkFieldsOK = useCallback(() => {
    return (isEmail(email) && isValidPassword(password) && passwordRepeat === password);
}, [email, password, passwordRepeat]);

Во втором useCallback подходе он ведет себя так:

  1. Изменения значения поля
  2. checkFieldsOK функция переделана
  3. useEffect запускается и проверяет правильность полей, обновляя состояние по мере необходимости
person Jayce444    schedule 10.01.2021

Во-первых, я бы подумал о перемещении выражения checkFieldsOK выше useEffect.

Тогда спросите себя, когда checkFieldsOK создается, называется?

Предполагая, что isEmail и isValidPassword являются функциями, объявленными вне вашего компонента, чтобы исправить проблему линтера, вам нужно либо заключить checkFieldsOK в useCallback:

const checkFieldsOK = useCallback(() => {
        return (
          isEmail(email) &&
          isValidPassword(password) &&
          passwordRepeat === password
        );
    }, [email, password, passwordRepeat])

Таким образом, checkFieldsOK будет обновлять свои входные данные всякий раз, когда изменятся email, password или passwordRepeat.

или переместите checkFieldsOK в useEffect и обновите зависимости эффектов:

    useEffect(() => {

      const checkFieldsOK = () => {
        return (
          isEmail(email) && 
          isValidPassword(password) && 
          passwordRepeat === password
         );
    }
        if (checkFieldsOK()) {
            setFieldsOK(true);
        } else {
            setFieldsOK(false);
        }
    }, [email, password, passwordRepeat])

Таким образом, ваш эффект будет срабатывать только при изменении состояния email, пароля или passwordRepeat.

Вы можете еще больше упростить:

    useEffect(() => {

      const fieldsOK = 
          isEmail(email) && 
          isValidPassword(password) && 
          passwordRepeat === password
        
       setFieldsOK(fieldsOK);

    }, [email, password, passwordRepeat])
person mtx    schedule 10.01.2021