Реагировать на предупреждение useEffect отсутствует зависимость - PullRequest
1 голос
/ 20 января 2020

В моем приложении React есть хранилище с избыточностью, в котором содержится пользователь со следующей моделью:

{
  id: "",
  name: "",
  email: "",
  isAdmin: false,
  client: { id: undefined },
  token: "",
  tokenExpiry: null
};

На простой странице я запрашиваю базу данных для других данных, связанных с этим пользователем. Для этого я использую преимущество useEffect hook:

  useEffect(() => {
    // Check JWT auth token and refresh if near expiry
    auth.refresh(
      { token: user.token, tokenExpiry: user.tokenExpiry },
      // Request user "field" data
      loadFields(user.client.id, user.token)
    );
  }, [user.client.id, user.token]);

При сборке React выдает предупреждение React Hook useEffect has missing dependencies: 'loadFields' and 'user.tokenExpiry'. Either include them or remove the dependency array.

Если я правильно понимаю useEffect, второе Параметр - это значения, которые Reach будет «наблюдать», после любого изменения компонент будет перерисован (аналогично тому, как работает componentDidUpdate) ...

Хотя в моем useEffect используются другие значения вызовите, я хочу повторно обработать эту функцию только когда user.client.id или user.token изменен. Это сделано для того, чтобы избежать ненужных повторных визуализаций при изменении других частей пользовательской модели, поэтому я не хочу добавлять user.tokenExpiry в качестве зависимости.

Поскольку функция loadFields также используется как функция вне useEffect logi c, я не могу поместить его в useEffect, поэтому я попытался добавить его как зависимость, но это вызывает повторный рендеринг l oop, так как он имеет вызов dispatch внутри него:

const loadFields = async (clientId, token) => {
  setIsLoading(true);
  try {
    await dispatch(fetchFields(clientId, token));
    setIsLoading(false);
  } catch (error) {
    setIsLoading(false);
    dispatch(resetFields());
  }
};

Так каков правильный путь к импелменту useEffect в этом сценарии?

Ответы [ 2 ]

1 голос
/ 21 января 2020

Чтобы включить функцию loadFileds в список зависимостей, попробуйте обернуть ее с помощью React.useCallback ловушки следующим образом

React.useCallback(async (clientId, token) => { ... }, []);

и добавить ее в список зависимостей. useCallback «запоминает» функцию и не создает ее при каждом рендеринге, поэтому loadFields остается одинаковым для всех рендеров и не вызывает effect, см. Документация .

Как насчет tokenExpiry - ну, иногда такие ситуации случаются, я обычно оставляю комментарий, который описывает, почему какой-то переменной нет в списке зависимостей.

1 голос
/ 20 января 2020

Либо добавьте все зависимости в массив

useEffect(() => {
  // Check JWT auth token and refresh if near expiry
  auth.refresh(
    { token: user.token, tokenExpiry: user.tokenExpiry },
    // Request user "field" data
    loadFields(user.client.id, user.token)
  );
}, [user.client.id, user.token, user.tokenExpiry]);

Или, скорее всего, он просто помечен вашим линтером Reaction-hooks, вы можете отключить его для этой строки.

useEffect(() => {
  // Check JWT auth token and refresh if near expiry
  auth.refresh(
    { token: user.token, tokenExpiry: user.tokenExpiry },
    // Request user "field" data
    loadFields(user.client.id, user.token)
  );
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user.client.id, user.token]);

Обычно я также оставляю комментарий выше переопределения по причине этого. Используйте это с осторожностью, так как когда вы вносите какие-либо изменения в ловушку эффекта, она может изменить то, что вы хотите, чтобы ловушка «наблюдала» за изменениями.

Предложение: Добавьте tokenExpry в массив и условно вызовите свою конечную точку, если Вы можете сказать, что это близко к необходимости освежения.

useEffect(() => {
  // Check JWT auth token and refresh if near expire
  if ( /* tokenExpiry almost expired */ ) {
    auth.refresh(
      { token: user.token, tokenExpiry: user.tokenExpiry },
      // Request user "field" data
      loadFields(user.client.id, user.token)
    );
  }
}, [user.client.id, user.token, user.tokenExpiry]);
...