本文章献给react以及redux入门开发者,作者将结合开发实际场景将react开发中常犯错误做出简单总结以及解释。
react组件的类型,以及不同类型组件的使用场景
首先,react组件分为有状态组件(即class组件、类组件)和纯函数组件(即UI组件、傻瓜组件)。
有状态组件的使用场景
有状态组件的创建方式为ES6继承形式
import React from 'react'
class YourComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
yourstate: '***'
}
}
componentWillMount(){}
render(){}
componentDidMount(){}
...
...
}
export default YourComponent
有的同学在看一些早些年的博客时可能会发现有状态组件的创建还有React.createClass这样的创建方式,这里需要说一下,这种组件的创建方式已经不再使用,目前官网推荐的创建方式为以上ES6的创建方式,可以理解我React.createClass的组件创建方式已经被废弃。
通过上面有状态组件的创建,我们需要注意:
1.必须要继承react.Component
2.constructor里要传入props
,并调用super(props),这是ES6的语法规定
3.this.state用来存放自身属性,假如要修改需要用this.setState(),而不是直接赋值
4.绑定方法的时候我们要用this
同时,我们也会发现,在有状态组件中,除了state
外,还会有各种生命周期方法,至此,我们不难想象出有状态组件的使用场景
1.我们的组件是有不同状态的,如:通过某按钮点击事件实现某表单项的显示与隐藏。
下面是伪代码
this.state = {
visible: flase,
}
changeVisible = () => {
this.setState({
visible: !this.state.visible,
})
}
render(){
return(
<div>
<Button onClick={this.changeVisible}>点我试试</Button>
{this.state.visible ? <Input /> : ''}
</div>
)
}
通过上面代码我们就实现了点击按钮来控制Input框的显示和隐藏了,这就是组件的不同状态的切换导致页面的改变,这里就需要用到有状态组件了。
2.我们需要异步获取组件中的数据。
下面是伪代码
this.state = {
data: [],
}
changeVisible = () => {
//这里省略异步请求方法,假设异步返回数据为res
this.setState({
data: res,
})
}
render(){
return(
<div>
<Button onClick={this.changeVisible}>点我获取数据</Button>
<p>{this.state.data}</p>
</div>
)
}
这里我们实现了通过点击事件获取p
标签中的内容,这里同上一个例子,实际上也是一种组件状态的切换,data
由[]
切换为请求回来的数据,为方便读者理解,我将数据状态的切换单独拿出来举例子。
我们上面实现了通过按钮点击事件触发异步请求来切换组件状态,那么我如何实现页面的自动触发请求呢?(此应用场景为页面加载自动数据),下面就是我们第三条需要使用有状态组件的理由
3.当我们的组件需要在不同的加载阶段干不同的事的时候
上面的话官方的来讲就是我们经常听到并使用的生命周期。
关于react的各个生命周期,这里将不再阐述,网上有各种厉害且详细的文章供参考,这里自做简单概述,生命周期,顾名思义,它是指一个组件从加载到卸载这样一个组件的生命过程,在这个生命过程中,会分各个阶段,各个阶段干着不同的事,各个阶段有着各个阶段适合干的事,当我们的组件有这种分阶段执行的方法时,那么我们就一次要用到有状态组件了。(这里写的有点通俗,单纯是为了纯小白理解,有点react基础的基本都可以忽略这段)
下面依然是伪代码:
this.state = {
data: [],
}
componentDidMount(){
//这里我们将省略异步请求,假设返回数据为data
this.setState({
data: res,
})
}
render(){
return(
<div>
<p>{this.state.data}</p>
</div>
)
}
上面的代码在没有事件触发的情况下自动执行了异步请求方法,这就是生命周期,针对本例子,这里需要强调一点的是,异步请求是要在componentDidMount这个生命周期里执行了,而不是componentWillMount,这是大多数react初学者都会想当然的犯的一个错误,虽然将异步请求写在后者是不会报错,但却不是符合组件的加载逻辑的,后者一般用于服务端渲染。
综上,我们介绍了react组件中的有状态组件,以及其使用场景。那么对于单纯的展示组件即UI组件,我们将用更简单方式来创建和使用。
纯函数组件的使用场景
提到纯函数组件,顾名思义,组件本身就是一个纯函数,关于什么是纯函数,这里将不再阐述,大致意思为不同的输入会有唯一确定的输出结果,下面我们来创建一个纯函数组件
import React from 'react'
const YourComponent = (props) => {
return (
<div>/*****/</div>
)
}
export default YourComponent
通过上面代码可以看出来,纯函数组件就是一个函数,我们可以用ES6的方式来创建,也可以用ES5的方式来创建,只不过我们在return
的时候,要遵守JSX的语法规则,其他的和普通函数没什么区别,它接收两个参数,一个为props
,一个为context
。
使用函数组件,我们需要注意,函数组件无法访问this对象,所有我们在使用函数组件时看到的都是props.***
、onClick={function}
这样的语句。
纯函数组件还有以下几个特点:
- 组件不会被实例化,整体渲染性能会得到提升
- 组件无法访问生命周期方法(函数当然没有生命周期了,这里是需要注意的,不要乱用生命周期)
- 函数组件只能访问传入的props,没有其他副作用。(关于react父子组件传值的问题将在后面的文章中详细讲解)
读者读到这里,想必以及意识到,函数组件的使用场景了,如果说有状态组件是为了满足某些特殊需求才用的,那么函数式组件就是在没有那些特殊需求的时候都可以用,也就是说,不到非用有状态组件的时候,我们都是可是使用函数组件的。并且我们是推荐使用函数组件。
读者可能会有疑问,那我们该如何去像有状态组件那样,在无事件触发的情况下自动获取数据呢?这里的解决方法有好多种,比如我们可以根据页面的逻辑进行调用初始化方法,也可以使用redux,来监听,实现初始化、(关于redux,我将在后面的文章中做详细的讲解包括使用场景)
纯函数组件相对于类组件的优势
- 纯函数组件在创建是不会创建实例,而没创建一个类组件都会创建一个实例。创建没必要的类组件,是对性能浪费
- 纯函数组件本身就是函数,不会有生命周期,因此在加载上也会变得快一点
- 纯函数组件没有副作用,是对副作用很好的解决方案,它让react更接近纯粹的函数式编程
关于纯函数组件的其他优势,这里将不再详细阐述,总之能用纯函数组件就用纯函数组件
在开发实际中会有这样的情况,有的程序员认为放着易懂的有状态组件不用,为什么非要用难懂的纯函数,于是整个应用下来清一色的类组件,并且有的类组件中,没有用到state
,没有用到生命周期,当然,项目照样能跑起来,只不过这对于应用的性能将不是一件好事。我们是不推荐这样做的。
关于react组件的优化
注意react优化的程序员写出来的react应用往往更加的流畅,加载更快。那么我们要如何进行react的优化呢?
这里我提两点最简单有效的优化方式
- 关于有状态组件,我们在创建时继承
PureComponent
,他不同于Component
,他会自动对组件前后属性进行浅比较,类似于shouldComponentUpdate
方法,用PureComponent
创建的组件将会减少应用中不必要的组件加载。 - 关于纯函数组件,自react16.6.6版本后,react加入了
react.memo
这样的高阶函数,他的作用类似PureComponent
,只不过他包装的是一个函数。
以上提到的两种优化方式,为随着React版本的更新官方提供的优化方式,我们在以后的开发中是推件这样做的。
关于react的细节优化问题,这是一个专门的话题,这里我将不在本文章做介绍,以后我会将各种react优化总结下来发布到我的博客中,下面为大家提供几个比较好的react优化文章的链接供大家参考。 - http://react-china.org/t/react/11562
-
https://www.jianshu.com/p/333f390f2e84
文章至此结束,感谢您的浏览!