翻译:ComponentDidMount和useEffect是不一样的,为什么

Author Avatar
Peipei Wong 8月 28, 2020
  • 在其它设备中阅读本文章

原文链接: https://medium.com/javascript-in-plain-english/componentdidmount-and-useeffect-are-not-the-same-heres-why-cea02f474c82

当组件挂载的时候进行一些设置是很常见的,例如网络请求。在hooks没有出现的时候,我们可以使用componentDidMount方法。在过渡到函数组件的时候,自然会寻求等效的hooks。

hooks和声明周期基于不同的原则。诸如compomentDidMount之类的方法是围绕声明周期和渲染时间展开,而hooks则是围绕state和与DOM的同步设计的。

许多程序员认为使用useEffect(fn, [])可以代替componentDidMount,虽然这不会导致大的错误产生,但是它仍会导致一些破坏程序的错误。两种方法在根本上是不一样的,你可能会得到预料之外的错误。程序员不应该认为hooks是组件挂载执行的方法。假如hooks以这样的方式工作,那么会影响你理解hooks。

state和props的捕获不一样

最明显的不用在使用异步方式的时候

class App extends Component {
  state = {
    name: ''
  }

  componentDidMount() {
    someResolve().thene(() => {
      console.log(this.state.name)
    })
  }

  onChange = (event) => {
    this.setState()
  }

  render() {
    return (
      <input value={this.state.name} onChange={this.onChange} />
    )
  }
}

这个组件看起来很简单,一旦它挂载了,它会调用一个异步函数,一旦异步函数成功执行,会将当前state的name值打印出来。让我们尝试将代码移植到函数组件上。

const App = () => {
  const [name, setName] = useState('')

  useEffect(() => {
    someResolve().then(() => {
      console.log(name)
    })
  }, [])

  const onChange = (event) =>{
    setName(event.target.value)
  }

  return (
    <input value={name} onChange={onChange} />
  )
}

上面的代码无法满足。当组件被创建,useEffect方法会捕获state和props的值,结果,用户即使输入了内容,console仍会打出一个空行。要告诉React使用最新的值,你必须将依赖项传给effect。props也是一样的逻辑。在这个例子中,effect比必须要使用compomentDidMount的class组件简单。

方法在不同的时刻被调用

React可以确定何时在componentDidMount中同步状态,让我们看一下组件的实际生命周期:

  1. 组件被挂载
  2. 根据render中返回的内容创建DOM
  3. componentDidMount被调用,state被更新
  4. DOM重新渲染,render中return的内容更新

可能有人希望我们在第一帧和第二帧中间看见闪烁,但是不会出现这样的情况,React检测到状态更新后,只打印第二帧。如果组件需要在DOM渲染时才计算元素的比例,这个是很有用的。

在组件挂载之后,hooks和useEffect都会执行。不同的是:hooks在DOM内容绘制之后执行。所以,如果在effect方法中同步更新state,用户会看到第二帧替换第一帧的闪烁。

你可以使用useEffectLayout获取带有hooks的旧行为,useEffectLayout在内容commit到页面前被调用。然而大多数都不会用到这个hook,大多数程序员仍坚持使用useEffect。

class组件围绕生命周期和渲染时间设计。函数组件旨在state和DOM的同步。思维方式的转变可能会导致一些奇怪的怪癖和错误,如果没有合适的知识很难去解决。简而言之,应该考虑“基于state,我的组件应该是什么样子,以及合适应该重新渲染”,这些问题将确保你的函数组件正常运行。