如何在React 18中使用严格模式:其新行为指南

411 阅读7分钟

React已经存在了相当长的一段时间了。每个主要的版本都向我们介绍了新的技术、工具和处理UI问题的方法。

React在2022年3月发布了v18,其中包括一些架构上的变化。这个版本主要集中在并发模式、新的React钩子和React的严格模式API的行为变化上。虽然严格模式已经是React的一项功能,但v18使其在捕捉早期bug方面更加有效,从而使代码库更加可预测。

在这篇文章中,你将了解严格模式以及它最初被引入的原因。你会看到它的各种特性,以及v18版本是如何改进其API并提供更好的钩子兼容性的。

严格模式正试图与React的基于悬念的架构一起为未来做好准备,使其在内省UI问题时更具弹性。让我们开始吧!

React的严格模式介绍

严格模式可以被认为是 ["use strict"](https://www.w3schools.com/js/js_strict.asp)符号。这是一段时间前在ECMAScript v5中引入的,确保了JavaScript的更严格的版本:

"use strict";
x = 3.1415;

上面的例子会抛出一个错误,因为x 没有被定义。请注意,在文件顶部添加"use strict" 是如何确保这一点的。在没有添加"use strict" 的情况下,你甚至可能不会得到这个错误,因为如果不受严格类型定义的约束,JavaScript往往会执行奇怪的行为(如"use strict" 、TypeScript、flow等)。

同样,React中的严格模式是一个开发专用的工具,在你编写React代码时执行更严格的警告和检查。

你可以为任何组件启用StrictMode ,只需在StrictMode ,像这样把组件的名字作为一个子道具包裹起来:

<StrictMode>
    <Button />
</StrictMode>
<StrictMode>
    <Navbar />
</StrictMode>

一个更值得推荐的方法是用StrictMode 来包装根App 组件。请注意,App 通常是create-react-app和Next.js中的根组件:

<StrictMode>
    <App />
</StrictMode/>

这样可以在整个React代码库中执行开发时间检查和警告。当然,要确保像这样导入StrictMode

import { StrictMode } from 'react'
 <StrictMode>
   .....
 </StrictMode>

或像这样:

import React from 'react'
 <React.StrictMode>
  .....
 </React.StrictMode>

现在,我们将深入研究严格模式的各种影响,它可以在开发过程中更早地帮助捕捉问题。

关于使用不安全生命周期方法的警告

React的基于类的生命周期方法经历了一系列的API变化。很多曾经被广泛使用的方法现在已被正式废弃,并被不鼓励使用,以支持更现代的API。

React的严格模式现在会警告开发者,如果他们使用这些被废弃的API,如componentWillMountcomponentWillReceiveProps 、和componentWillUpdate 。这些现在被认为是不安全的使用,以至于React在这些API名称上添加了一个UNSAFE 前缀:

  • UNSAFE_componentWillMount
  • UNSAFE_componentWillReceiveProps
  • UNSAFE_componentWillUpdate

严格模式甚至足够聪明,如果正在使用的任何第三方包包含这些废弃的API,它会警告开发者。你可以自己修改这些包,或者选择一个替代品。

推荐createRef API而不是传统的字符串ref

如果你曾经使用过React,当基于类的架构是创建组件的事实方式时,你可能已经使用了字符串ref API:

class Form extends Component {
  render() {
    return <input onClick={() => this.focus()} ref='input' />;
  }
  focus() {
    console.log(this.refs.input.value);
  }
}

虽然这种API可读性强,使用方便,但由于一些原因,现在被认为是一种遗留问题,包括:

  • 一个被包裹的组件无法弄清它的子组件是否已经有了一个ref。这个问题可以用回调ref模式来解决。
  • 字符串ref API很难用类型检查器来阅读和进行静态分析。

React的严格模式警告开发者使用回调模式或更现代的createRef API来代替。

关于废弃的findDOMNode 使用的警告

[findDOMNode](https://blog.logrocket.com/managing-dom-components-reactdom/)是一个基于类的API,用于从任何组件中锁定DOM树深处的一个元素:

class Layout extends Component {


componentDidMount() {
  const nodeElement = ReactDOM.findDOMNode(this);
}


     render () {
     return <Navigation>{this.props.children}</Navigation>;
     }
    }

这看起来很好,但它实际上在React的抽象原则中造成了问题。

父元素必须确保其子元素向下延伸并呈现正确的DOM节点。一个很大的缺点是,findDOMNode 仅仅是一个一次性的调用API,所以如果任何节点元素由于一些状态的更新而被向下改变,它将不会被反映和更新到findDOMNode API。

考虑到所有这些缺点,严格模式警告你不要使用这个API,它可能在未来的React版本中被删除。

大多数时候,DOM元素现在可以使用ref 作为目标。你可以简单地将一个ref 引用附加到你需要定位的元素上:

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();    
}

// handle textInput.current logic here //
  render() {
    return (
      <input
          type="text"
          ref={this.textInput} 
   />       
    );
  }
}

检测意外的副作用

React的严格模式对流行的内置钩子做了一些有趣的事情,如useStateuseMemouseReducer 。具体来说,它在开发中调用这些函数两次,在生产模式中调用一次(如预期)。

这在调试代码时可能会造成一些混乱,但通过这样做,严格模式确保了检查潜在的内存泄漏。这也有助于使严格模式的代码更具有确定性。

不仅仅局限于功能组件,在基于类的架构中也可以发现两次调用函数的相同行为,比如在constructorrendershouldComponentUpdate ,等等。

如果你使用的是create-react-app,整个应用的严格模式是默认的。当使用这些钩子或类组件中的状态更新器函数时,你会看到即使是控制台信息也会被记录两次。

在v18之前,当函数被调用两次时,React会立即让第二个console.log 方法沉默。但是,在v18中,React并没有压制任何日志,以使开发者有更多的透明度。所有这些日志现在都会在任何函数、钩子等的双重调用中被调用两次。

对遗留的上下文API的警告

与 refs API 类似,我们也有一个传统的上下文 API。严格模式警告不要使用传统的上下文 API,因为它将在未来的版本中被删除。相反,我们有一个更现代的上下文API,使用提供者-消费者模式:

const ThemeContext = React.createContext('dark')

// consume it here
 <ThemeContext.Provider value={data}>
     {children}
</ThemeContext.Provider>

这是现在使用新的上下文API处理应用程序状态上下文的推荐方式。

React v18的卸载和重挂架构

React v18引入了新的关于卸载和重挂的严格模式行为。现在,每个元素在被卸载和重新挂载时,其状态和效果与元素第一次被挂载时相同。

一个典型的挂载和重新挂载周期可能是这样的:

  • 元素第一次被挂载
  • 产生副作用
  • 严格模式现在模仿了效果的破坏
  • 副作用将被应用于挂载的组件

这使得React代码更有弹性,并有助于保存UI的状态。例如,如果用户在第一个标签页上,并立即在第一个和第二个标签页之间来回切换,React需要确保正确的元素块被加载和销毁,同时保留正确的UI状态和副作用。

从v18开始,严格模式有这个额外的开发专用的行为。

总结

你现在已经涵盖了React v18的严格模式更新中的所有内容!

我们已经看到严格模式是如何影响开发模式的工具的。它有自己的一套规则和行为,确保对代码库的严格警告和检查。这不仅可以帮助开发人员使代码库适应未来,也可以帮助他们进行重构。

官方的React团队建议在整个应用范围内执行严格模式,以获得它的最大效益。对于未来的React版本,预计严格模式将获得更多的功能,以帮助像我们这样的开发者获得更好的工具支持。