Реакция-зацепка ESLint - правило «исчерпывающего действия» - разве нет лучшего способа? - PullRequest
2 голосов
/ 03 марта 2020

Существует довольно много информации об этом правиле, но я действительно считаю, что должен быть найден какой-то лучший способ обработки альтернативы componentDidMount.

Похоже, что это также сбивает с толку многих разработчиков и довольно сложно написать обходные пути для наиболее распространенных вариантов использования:

https://github.com/facebook/react/issues/14920

Здесь я привожу несколько примеров, которые на самом деле не так-то просто найти. установить с этим правилом:

Пример 1 : Инициализация приложения - или проверить куки / локальное хранилище после загрузки приложения и установить их в контексте:

import React, { useState, createContext, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import CookieHandler from '../helpers/CookieHandler';
import Loading from '../components/common/Loading';

const defaultValues = {
  authorization: {
    loggedIn: false,
    isAdmin: false,
  },
  dispatchAuthorization: () => {},
};

const LoginContext = createContext(defaultValues);

const reducer = (state, authorization = { loggedIn: false, isAdmin: false }) => {
  const { loggedIn, isAdmin } = authorization;
  return { loggedIn: !!loggedIn, isAdmin: !!isAdmin };
};

const LoginContextProvider = ({ children }) => {
  const [authorization, dispatchAuthorization] = React.useReducer(reducer, defaultValues.authorization);
  const [mounted, setMounted] = useState(false);
  const { i18n } = useTranslation();

  const setLoginData = (token, isAdmin) => {
    if (token) {
      dispatchAuthorization({
        loggedIn: true,
        isAdmin: isAdmin,
      });
    }
    setMounted(true);
  };

  const setLanguage = (language) => {
    i18n.changeLanguage(language);
    CookieHandler.setLanguage(language);
  };

  const loginUser = data => {
    CookieHandler.setToken(data.token);
    CookieHandler.setAdmin(data.isAdmin);
    setLoginData(data.token, data.isAdmin);
  };

  const removeLoginData = () => {
    CookieHandler.logout();
    dispatchAuthorization({
      loggedIn: false,
      isAdmin: false,
    });
  };

  useEffect(() => {
    const token = CookieHandler.getToken();
    const isAdmin = CookieHandler.getAdmin();
    const language = CookieHandler.getLanguage();

    if (token) {
      setLoginData(token, isAdmin);
    } else if (authorization.loggedIn || authorization.isAdmin) removeLoginData();

    if (language) setLanguage(language);
    setMounted(true);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  if (!mounted) return <Loading />;

  return (
    <LoginContext.Provider
      value={{
        authorization,
        dispatchAuthorization,
        setLoginData,
        loginUser,
        setLanguage,
        logoutUser: removeLoginData,
      }}
    >
      {children}
    </LoginContext.Provider>
  );
};

const LoginContextConsumer = LoginContext.Consumer;

export { LoginContext, LoginContextProvider, LoginContextConsumer };

Здесь я хочу, чтобы useEffect действительно назывался один раз , приложение загружено, и никогда больше. Но, согласно eslint, я должен добавить переменную авторизации в массив dept, но я не хочу этого делать. Поскольку каждый раз, когда происходит изменение в авторизации, весь INIT-Prozess будет запускаться снова и снова. Я думаю, что функция инициализации, которая запускается, когда компонент / или приложение запускается, совершенно необходима, не думая об изменении переменных позже?

Пример 2: Использование функций, которые приходят из ловушек , Пример с act-i18next :

...
import { useTranslation } from 'react-i18next';
...

const MyComponent = ({ someId }) => {
 const { t } = useTranslation();
 const [data, setData] = useState(null);
  useEffect(() => {
    const someAsyncFetch = async () => {
  try {
    const data = await asyncFetchData({
      someId,
    });
    setData(data);
    toastr.success(t('your.data.was.fetched.successfully'));
  } catch (e) {
    console.log(e);
    toastr.error(t('your.data.can.not.be.fetched'));
  }
 };
    someAsyncFetch();
  }, [someId]);
}

В этом примере я хочу получить все данные при визуализации моего компонента или при изменении someId. Когда данные загружаются или приходит ошибка - я запускаю сообщение toastr с функцией перевода t , которое у меня попадает в ловушку. Но я не хочу получать новые данные каждый раз, когда пользователь переключает свой язык. Но eslint хочет, чтобы я поместил t в массив deps, что вызывает повторную визуализацию компонента и загрузку новых данных каждый раз, когда пользователь переключает язык. Более того, следует ожидать, что в будущем будет появляться все больше и больше таких хуков-функций, которые мы, возможно, захотим использовать в useEffects.

Пример 3: Одна переменная зависит от другие переменные

  useEffect(() => {
    if (error === null) {
      const data = doSomethingWithMyValue(value1);
      setMyData(data);
    } else {
      showSomeErrorText(); //or do nothing
    }
  }, [value1]);

Если я хочу, чтобы только при изменении значения 1 сработала функция doSomethingWithMyValue, но не при изменении ошибки. Когда мы помещаем ошибку в массив useEffects deps, тогда весь лог c нарушается, потому что useEffect будет срабатывать при каждом изменении ошибки. И это то, чего я не хочу.

Я также пытался сделать какой-то обходной путь с подключенной переменной и useCallback, но мне кажется, что useEffect запускает ненужные много раз, и почему-то все медленнее.

Итак, есть ли где-нибудь логи c -слова или нам действительно нужно использовать всю эту заметку и useCallbacks et c. чтобы предотвратить серьезные проблемы?

Спасибо за любые отзывы!

...