一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
前言
大家好呀,我是L同学。在上篇文章中react基础(十三)我们学习了react中的forwardRef的使用和Portals的使用。今天我们学习fragment和strictMode。
fragment
我们通过计数器这个案例来讲解fragment。
import React, {PureComponent} from 'react'
export default class App extends PureComponent {
constructor() {
super()
this.state = {
counter: 0
}
}
render() {
return (
<div>
<h2>当前计数: {this.state.counter}</h2>
<button onClick={e => this.increment()}>+1</button>
</div>
)
}
increment() {
this.setState({
counter: this.state.counter + 1
})
}
}
我们可以看到h2元素和按钮外面有一层div元素。
如果不想要这层div元素,可以直接把它去掉吗?答案是不可以的,去掉会报错,在jsx中只能有一个根元素。
那么我不想要渲染这个没有用的外层div元素,该怎么办呢?
此时可以使用Fragment。Fragment允许你将子列表分组,不需要向DOM添加额外节点。
render() {
return (
<React.Fragment>
<h2>当前计数: {this.state.counter}</h2>
<button onClick={e => this.increment()}>+1</button>
</React.Fragment>
)
}
我们也可以这样写。先从react中导入。
import React, { PureComponent, Fragment } from 'react'
<Fragment>
<h2>当前计数: {this.state.counter}</h2>
<button onClick={e => this.increment()}>+1</button>
</Fragment>
此时h2元素和按钮外层没有渲染多余的标签。
在react中,还提供了Fragment的短语法,它看起来箱空标签<></>。
<>
<h2>当前计数: {this.state.counter}</h2>
<button onClick={e => this.increment()}>+1</button>
</>
同样,可以正常渲染。
接下来,我们渲染数组。
this.state = {
counter: 0,
friends: [
{name: 'haha', age: 18},
{name: 'xixi', age: 20},
{name: 'lili', age: 22}
]
}
<>
<h2>当前计数: {this.state.counter}</h2>
<button onClick={e => this.increment()}>+1</button>
<div>
{
this.state.friends.map((item, index) => {
return (
<>
<div>{item.name}</div>
<p>{item.age}</p>
<hr/>
</>
)
})
}
</div>
</>
我们可以看到它们的结构。
在渲染数组时,我们通常会添加key来进行性能优化。
需要注意的是,如果我们需要在Fragment中添加key,那么就不能使用短语法。
我们只能这么写。
<div>
{
this.state.friends.map((item, index) => {
return (
<Fragment key={item.name}>
<div>{item.name}</div>
<p>{item.age}</p>
<hr/>
</Fragment>
)
})
}
</div>
StrictMode
StrictMode是一个用来突出显示应用程序中潜在问题的工具。它和Fragment一样不会渲染任何可见的UI。StrictMode为它的后代元素触发额外的检查和警告。严格模式检查仅在开发模式下运行,它们不会影响生产构建。
StrictMode可以为应用程序的任何部分开启严格模式。在以下代码中,会对Home组件以及它的所有后代元素都进行检查。但是不会对Profile组件进行严格模式检查。
export default class App extends PureComponent {
render() {
return (
<div>
<StrictMode>
<Home/>
</StrictMode>
<Profile/>
</div>
)
}
}
严格模式检查检查的是什么呢?接下来我们对进行严格检查的Home组件和不进行严格检查的Profile组件进行比较。
1. 识别不安全的生命周期
我们在Home组件和Profile组件中使用componentWillMount生命周期函数。
Home组件。
class Home extends PureComponent {
componentWillMount() {
console.log('home componentWillMount');
}
render() {
return (
<div>Home</div>
)
}
}
Profile组件。
class Profile extends PureComponent {
componentWillMount() {
console.log('Profile componentWillMount');
}
render() {
return (
<div>Profile</div>
)
}
}
我们可以看到使用这个生命周期函数报了警告。这是因为这个生命周期函数不推荐使用了,按照它的提示,我们使用UNSAFE_componentWillMount。
UNSAFE_componentWillMount() {
console.log('home componentWillMount');
}
同样地,Profile组件也进行替换。
此时,我们看到UNSAFE_componentWillMount在严格模式下下是不被推荐的,提示在Home组件中进行更新。
2. 使用过时的ref API
在react基础(十一)这篇文章中,我们介绍了ref的使用,其中ref中传入字符串是不推荐的。那么在严格模式下传入字符串会怎么样呢?
<div ref="title">Home</div>
<div ref="title">Profile</div>
我们可以看到警告提示在严格模式下应该尽量避免使用字符串的ref,而非严格模式下是可以使用的。
3. 使用废弃的findDOMNode方法
在之前的React API中,可以通过findDOMNode来获取DOM,不过已经不推荐使用了。
4. 检查意外的副作用
进行严格模式检查Home组件的constructor会被调用两次。这是严格模式下故意进行的操作,让你来看看在这里写的一些逻辑被调用多次时,是否会产生一些副作用。在生产环境中,是不会被调用两次的。
我们来测试下。
constructor(props) {
super(props)
console.log('home constructor');
}
我们可以看到在Home组件中constructor被调用了两次,而Profile组件的constructor被调用了一次。
5. 检查过时的context API
早期的Context是通过static属性声明Context对象属性,通过getChildContext返回Context对象等方式来使用Context的,目前这种方式已经不推荐使用。