使用React钩子use的React生命周期

时间:2019-10-19 03:24:30

标签: javascript reactjs

我目前正在通过生命周期事件(例如class)将应用文件从componentDidMount更改为带有functions钩子的useEffect

对于大多数文件,我没有看到任何问题,但是在下面,我遇到了性能问题,该应用程序冻结了。控制台中的错误或警告为零,但我的机器和Chrome浏览器增加了此标签上使用的内存。

我错过了什么?

基于旧类的文件代码

listener: any;

componentDidMount() {
  const { firebase } = this.props;
  this.listener = firebase.onAuthUserListener(
    (authUser: any) => {
      localStorage.setItem('authUser', JSON.stringify(authUser));
      this.setState({ authUser });
    },
    () => {
      localStorage.removeItem('authUser');
      this.setState({ authUser: null });
    }
  );
}

componentWillUnmount() {
  this.listener();
}

带有钩子的新功能(导致性能问题)

const listener = () => {
  firebase.onAuthUserListener(
    (authUser: any) => {
      localStorage.setItem('authUser', JSON.stringify(authUser));
      setState(authUser);
    },
    () => {
      localStorage.removeItem('authUser');
      setState(null);
    }
  );
};

useEffect(() => {
  listener();
  return () => {
    listener();
  };
});

也许值得一提的是,我将TypeScript与React结合使用。

3 个答案:

答案 0 :(得分:2)

onAuthUserListener返回一个要退订的函数。卸载组件时应使用此选项。

在您的代码中,您没有返回取消订阅功能。

const listener = () => {
  firebase.onAuthUserListener(..)    // problem here no return
}

因此,在useEffect下,您应该正确分配它,并在useEffect的退货中使用它。

const [user, setUser] = React.useState(null);

useEffect(
  () => {
    //             v------ proper assignment.
    const listener = firebase.onAuthUserListener(
      (authUser: any) => {
        localStorage.setItem('authUser', JSON.stringify(authUser));
        setUser(authUser);
      },
      () => {
        localStorage.removeItem('authUser');
        setUser(null);
      }
    );

    return () => listener();
  }
  , [] // no deps
);

答案 1 :(得分:1)

这可能是错误:

useEffect(() => {
  listener();
  return () => {
    listener();  <--- here
  };
});

问题是,为了触发listener();呼叫,需要更改什么状态?

我认为:

const listener = () => {
  firebase.onAuthUserListener(
    (authUser: any) => {
      localStorage.setItem('authUser', JSON.stringify(authUser));
      setState(authUser);
    },
    () => {
      localStorage.removeItem('authUser');
      setState(null);
    }
  );
};

应转换为React Hook。干杯!

答案 2 :(得分:0)

useEffect需要一个依赖项数组作为第二个参数,否则它将继续在每个渲染器上运行。由于您正在更新状态,因此会不断重复

useEffect(() => {
  listener();
  return () => {
    listener();
  };
}, []);

Docs

您可以使用Runaway Effects或ESLint之类的工具进行静态分析,以预先找出这些问题。