如何正确摆脱 UNSAFE_componentWillMount

How to properly get rid of UNSAFE_componentWillMount

对于我从其他开发人员那里继承的 React 应用程序,其中一个页面包括:

import { getLogUser } from "../../appRedux/actions/authAction";

constructor(props) {
    super(props);
    this.state = {
        user: null,
    };
}

UNSAFE_componentWillMount() {
    let user = getLogUser();
    this.setState({ user });
    // user state is used inside the render part
}

componentDidMount = () => {
    let { username } = getLogUser();
    // ... username is used inside some logic within the componentDidMount method.

我想摆脱 UNSAFE_componentWillMount 方法。

  1. 如果我在 constructor 中使用 user: getLogUser(),我可以删除 UNSAFE_componentWillMount 部分吗?
  2. 如果那确实是正确的方法,那我不也应该这样做吗? 替换里面的let { username } = getLogUser(); componentDidMountlet { username } = this.state.user?

首先,让我先解释一下什么是UNSAFE_componentWillMount

来自 defination

UNSAFE_componentWillMount() is invoked just before mounting occurs. It is called before render(), therefore calling setState() synchronously in this method will not trigger an extra rendering.

所以意味着UNSAFE_componentWillMount()会在render()之前被调用(组件还没有在UI上)。这与在 render()

之后调用的 componentDidMount() 完全相反

要更深入地了解 React 团队为何要将其 UNSAFE 作为弃用函数,您可以查看 this RFC.

跟进您的问题

Can I remove the UNSAFE_componentWillMount part if I use user: getLogUser() inside the constructor?

constructor 中调用函数的好处与 UNSAFE_componentWillMount 类似,可确保您的数据在呈现触发器之前可用。

所以我同意你的情况,只要它不是异步函数(比如 async/await)你就可以这样做

constructor(props) {
    super(props);
    this.state = {
        user: await getLogUser(), //YOU CANNOT DO THIS WAY
    };
}

这是正确的方法

constructor(props) {
    super(props);
    this.state = {
        user: getLogUser(), //no asynchronous call
    };
}

那么如果getLogUser()是异步的呢? componentDidMount 派上用场了。它将在第一次呈现后触发,但您可以根据需要等待数据,并且不会阻塞 UI 的交互(或者您可以显示正在加载 UI )

componentDidMount = async () => {
   const user = await getLogUser()
   setState({ user })
}

render() {
  //show loading if `user` data is not populated yet
  const { user } = this.state
  if(!user) {
     return <div>Loading</div>
  }
}

If that is indeed the correct way to do it, shouldn't I then also replace let { username } = getLogUser(); inside componentDidMount with let { username } = this.state.user?

是的,的确如此。如果您已经在 constructor 中填充了 user 状态,则可以执行此操作,但您需要确保您的函数将在短时间内执行。如果您的函数调用时间过长,将导致 UI 由于渲染受阻而出现问题。

//trigger before first rendering
constructor(props) {
    super(props);
    this.state = {
        user: getLogUser(), //no asynchronous call
    };
}

//trigger after first rendering
componentDidMount = () => {
    const { username } = this.state.user;
}