React的无状态和有状态组件详解

来源:程序思维浏览:2721次
下面我给大家介绍一下什么是react有状态组件和无状态组件,这也是面试时长问的问题。

React的无状态和有状态组件详解

React中创建组件的方式
在了解React中的无状态和有状态的组件之前,先来了解在React中创建组件的三种方式:

ES5写法:React.createClass;
ES6写法:React.Component;
无状态的函数写法,又称为纯组件SFC。
React.createClass
React.createClass是React刚开始推荐的创建组件的方式。这是ES5的原生的JavaScript来实现的React组件。React.createClass这个方法构建一个组件“类”,它接受一个对象为参数,对象中必须声明一个render()方法,render()方法将返回一个组件实例。例如:

import React from 'react'
import ReactDOM from 'react-dom'

const SwitchButton = React.createClass({
    getDefaultProp: function () {
        return {open: false}
    },
    getInitialState: function () {
        return {open: this.props.open};
    },
    handleClick: function (event) {
        this.setState({open: !this.state.open});
    },
    render: function () {
        var open = this.state.open, className = open ? 'switch-button open' : 'btn-switch';
        return (
            <label className={className} onClick={this.handleClick.bind(this)}>
                <input type="checkbox" checked={open}/>男
            </label> );
    }
});
ReactDOM.render(<SwitchButton/>, document.getElementById('root'));

React.createClass是用来创建有状态的组件,这些组件在使用时是要被实例化的,并且可以访问组件的生命周期方法。不过React.createClass创建React组件有其自身的问题存在:

React.createClass会自动绑定函数方法,导致不必要的性能开销,增加代发过时的可能性;
React.createClass的mixins不够自然、直观,易读性差。
React.Component
React.Component是以ES6的形式来创建React组件,也是现在React官方推荐的创建组件的方式,其和React.createClass创建的组件一样,也是创建有状态的组件。React.Component正在逐渐取代React.createClass,上面的例子使用React.Component实现如下。

import React from 'react'
import ReactDOM from 'react-dom'

class SwitchButton extends React.Component {
    constructor(props) {
        super(props)
        this.state = {open: this.props.open}
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick(event) {
        this.setState({open: !this.state.open})
    }

    render() {
        let open = this.state.open, className = open ? 'switch-button open' : 'btn-switch'
        return (<label className={className} onClick={this.handleClick}>
            <input type="checkbox" checked={open}/> 男
        </label> )
    }
}

SwitchButton.defaultProps = {open: false}
ReactDOM.render(<SwitchButton/>, document.getElementById('root'))

相比React.createClass方式,React.Component带来了诸多语法上的改进

import
ES6使用import方式替代ES5的require方式来导入模块,其中import { }可以直接从模块中导入变量名,此种写法更加简洁直观。

初始化 state
在ES6的语法规则中,React的组件使用的类继承的方式来实现,去掉了ES5的getInitialState的hook函数,state的初始化则放在constructor构造函数中声明。

this绑定
React.Component创建组件时,事件函数并不会自动绑定this,需要我们手动绑定,不然this将不会指向当前组件的实例对象。
以下有三种绑定this的方法:
1,在constructor中使用bind()进行硬绑定。

constructor() {
  this.handleClick = this.handleClick.bind(this);
}

直接在元素上使用bind()绑定。
<label className={className} onClick={this.handleClick.bind(this)}>

ES6 有个很有用的语法糖:Arrow Function(箭头函数)它可以很方便的使this直接指向class SwitchButton。
<label className={className} onClick={()=>this.handleClick()}>

无状态组件
无状态的函数创建的组件是无状态组件,它是一种只负责展示的纯组件,它的特点是不需要管理状态state,数据直接通过props传入,这也符合 React 单向数据流的思想。例如:

function HelloComponent(props) {
    return <div>Hello {props.name}</div>
}

ReactDOM.render(<HelloComponent name="marlon"/>, mountNode)

对于这种无状态的组件,使用函数式的方式声明,会使得代码的可读性更好,并能大大减少代码量,箭头函数则是函数式写法的最佳搭档。

const Todo = (props) => (
    <li onClick={props.onClick}
        style={{textDecoration: props.complete ? "line-through" : "none"}}>
        {props.text}
        </li> )

上面定义的 Todo 组件,输入输出数据完全由props决定,而且不会产生任何副作用,对于props为 Object 类型时,还可以使用 ES6 的解构赋值。

const Todo = ({onClick, complete, text, ...props}) => (
    <li onClick={onClick} style={{textDecoration: complete ? "line-through" : "none"}} {...props} >
        {props.text}
        </li> )

无状态组件一般会搭配高阶组件(简称:HOC)一起使用,高阶组件用来托管state,Redux 框架就是通过 store 管理数据源和所有状态,其中所有负责展示的组件都使用无状态函数式的写法。

无状态组件内部其实是可以使用ref功能的,虽然不能通过this.refs访问到,但是可以通过将ref内容保存到无状态组件内部的一个本地变量中获取到。例如,下面这段代码可以使用ref来获取组件挂载到DOM中后所指向的DOM元素:

function TestComp(props) {
    let ref;
    return (
        <div ref={(node) => ref = node}></div> )
}

无状态组件 vs 有状态组件

无状态组件:无状态组件(Stateless Component)是最基础的组件形式,由于没有状态的影响所以就是纯静态展示的作用。一般来说,各种UI库里也是最开始会开发的组件类别。如按钮、标签、输入框等。它的基本组成结构就是属性(props)加上一个渲染函数(render)。由于不涉及到状态的更新,所以这种组件的复用性也最强。

有状态组件:在无状态组件的基础上,如果组件内部包含状态(state)且状态随着事件或者外部的消息而发生改变的时候,这就构成了有状态组件(Stateful Component)。有状态组件通常会带有生命周期(lifecycle),用以在不同的时刻触发状态的更新。这种组件也是通常在写业务逻辑中最经常使用到的,根据不同的业务场景组件的状态数量以及生命周期机制也不尽相同。

在React中,我们通常通过props和state来处理两种类型的数据。props是只读的,只能由父组件设置。state在组件内定义,在组件的生命周期中可以更改。基本上,无状态组件(也称为哑组件)使用props来存储数据,而有状态组件(也称为智能组件)使用state来存储数据。

总的来说:无状态函数式写法 优于React.createClass,而React.Component优于React.createClass。能用React.Component创建的组件的就尽量不用React.createClass形式创建组件。
精品好课
最新完整React视频教程从入门到精通纯干货纯实战
React是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习React高薪就...
jQuery视频教程从入门到精通
jquery视频教程从入门到精通,课程主要包含:jquery选择器、jquery事件、jquery文档操作、动画、Ajax、jquery插件的制作、jquery下拉无限加载插件的制作等等......
React实战视频教程仿京东移动端电商
React是前端最火的框架之一,就业薪资很高,本课程教您如何快速学会React并应用到实战,对正在工作当中或打算学习React高薪就业的你来说,那么这门课程便是你手中的葵花宝典。
HTML5基础入门视频教程易学必会
HTML5基础入门视频教程,教学思路清晰,简单易学必会。适合人群:创业者,只要会打字,对互联网编程感兴趣都可以学。课程概述:该课程主要讲解HTML(学习HTML5的必备基础语言)、CSS3、Javascript(学习...
HTML5视频播放器video开发教程
适用人群1、有html基础2、有css基础3、有javascript基础课程概述手把手教你如何开发属于自己的HTML5视频播放器,利用mp4转成m3u8格式的视频,并在移动端和PC端进行播放支持m3u8直播格式,兼容...
Vue2+Vue3+ES6+TS+Uni-app开发微信小程序从入门到实战视频教程
2021年最新Vue2+Vue3+ES6+TypeScript和uni-app开发微信小程序从入门到实战视频教程,本课程教你如何快速学会VUE和uni-app并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己...
VUE2+VUE3视频教程从入门到精通(全网最全的Vue课程)
VUE是目前最火的前端框架之一,就业薪资很高,本课程教您如何快速学会VUE+ES6并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习VUE高薪就...
最新完整React+VUE视频教程从入门到精,企业级实战项目
React和VUE是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React和VUE并应用到实战,教你如何解决内存泄漏,常用库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习Re...
收藏
扫一扫关注我们