2

关于这条规则有很多信息,但我真的认为应该有一些更好的方法来处理componentDidMount-alternative。

看起来它也让很多开发人员感到困惑,并且很难为最常见的用例编写变通方法:

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

在这里,我提供了一些确实不容易使用此规则设置的示例:

示例 1:应用程序的初始化 - 或在应用程序加载后检查 cookies/localstorage,并在上下文中设置它们:

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:使用来自钩子的函数。react-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 时获取所有数据。当数据加载或出现错误时 - 我使用我在钩子中获得的翻译函数t触发 toastr 消息。但我不想每次用户切换语言时都获取新数据。但是 eslint 希望我将 t 放入 deps 数组中,这会导致每次用户切换语言时重新渲染组件并加载新数据。而且,我们应该预料到未来会出现越来越多的此类钩子函数,我们最终可能希望在 useEffects 中使用它们。

示例 3:一个变量依赖于其他变量

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

如果我只希望在 value1 更改时,函数 doSomethingWithMyValue 将被触发,但不会在错误更改时触发。当我们将 error 放入useEffectsdeps 数组时,整个逻辑就被破坏了,因为每次 error 发生变化时都会触发 useEffect。这是我不想要的。

我还尝试使用已安装的变量和 进行某种解决方法useCallback,但是它看起来对我来说是useEffect不必要的多次触发,并且不知何故整个事情变慢了。

那么是否存在逻辑问题或者我们真的需要使用所有这些备忘录useCallbacks等来防止一些严重的问题?

感谢您的任何反馈!

4

0 回答 0