Как вы препятствуете запуску функций внутри useEffect более одного раза? - PullRequest
1 голос
/ 11 марта 2020

Существует правило ESLint exhaustive-deps, которое проверяет массив зависимостей ваших хуков (например: useEffect). Мой вопрос заключается в том, что контент useEffect будет вызываться чаще из-за таких вещей, как отслеживание функций.
Это может оказать негативное влияние, когда вызов API находится внутри эффекта, потому что вы хотели бы только API чтобы быть вызванным один раз.
Я мог бы разбить эффект больше, и, возможно, это поможет с массивом dep ... может быть, нет ...

Как вы предотвращаете запуск контента больше чем нужно? Для меня, чтобы предотвратить дополнительные вызовы к службе API, мне нужно либо игнорировать правило lint (нет!), либо иметь больше проверок вокруг моего кода, а также иметь локальное состояние о статус:

Пример для предотвращения вызова сеанса и API более одного раза:

useEffect(() => {
    if (!saveValues) {  // is this an anti-pattern?
      return;
    }
    if (!sessionId && !wasSaving && savingForm) {
      initSession().then(() => { // 1st call to session service to get Id
        setSendRequest(true); // set local state that it's safe to send API request because I have my session ready
      });
    } else if (sendRequest && sessionId) {
      setSendRequest(false); // immediately set local state back to false so the previous block doesnt fire.
      try {
        const fields = userFields
          .filter(field => !isEmpty(saveValues[field.name]))
          .map(field => {
              name: field.name,
              value,
            };
          );
        insertUser({ sessionId, fields, config, newRoles }) // here's my API call now
          .then(() => saveSession(sessionId)) // 2nd call to session service req'd
      } catch (err) {
        const message = err.message.split('desc = ')[1];
        setSaveRequestError(message);
        setSavingForm(false);
        setSaveModalOpen(false);
        quitSession(sessionId);
      }
    }
    return () => {
      if (sessionId) {
        quitSession(sessionId);
      }
    };
  }, [
    initSession,
    insertUser,
    quitSession,
    roles.rolesList,
    saveSession,
    saveValues,
    savingForm,
    sendRequest,
    sessionId,
    userFields,
    wasSaving,
  ]);

в качестве примечания, интересно, что зацепки для состояния, такие как setSaveRequestError, setSavingForm do не отображается в массиве dep ...

Ответы [ 3 ]

0 голосов
/ 12 марта 2020

Из-за реагирующей документации здесь и здесь лучше поместить каждое из ваших условий в отдельный useEffect, а не в один сложный. Каждый useEffect имеет свой собственный массив зависимостей и выполняет задание c.

0 голосов
/ 12 марта 2020

Если вы просто хотите избежать его повторного выполнения (и не хотите передавать пустой массив dep), useRef - ваш друг, так как он не переопределяет компонент (не состояние):

let hasBeenExecuted = useRef(false);
//In effect
if(!hasBeenExecuted.current) {
    // Do stuff
    hasBeenExecuted.current = true
}
0 голосов
/ 11 марта 2020

useEffect вызывается при каждом изменении передаваемой ему зависимости и выполняет весь код внутри него.

Примечание: useEffect (() => {}, [dependency1, dependency2 ...])

Если вы хотите, чтобы ваш код внутри useEffect вызывался только при начальной загрузке компонента, передайте пустой массив в качестве зависимости.

...