React中的无状态和有状态组件

特别声明:小站已开通年费VIP通道,年费价格为 ¥365.00元。如果您喜欢小站的内容,可以点击开通会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!(^_^)

组件的概念在Web中应用的场景已经相当广泛了。而React是专注于View层的,组件也是React核心理念之一,一个完整的应用将由一个个独立的组件拼装而成。组件也是React最基础的一部分,欲想征服React,那么了解和编写组件就显得尤为重要。

上一篇文章,咱们就写了一个最简单的React组件,而且在文章末尾,咱们留了一个问题,怎么创建无状态和有状态的React组件?接下来,就一起来了解React中的无状态和有状态的组件。

React中创建组件的方式

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

  • ES5写法:React.createClass
  • ES6写法:React.Component
  • 无状态的函数写法,又称为纯组件SFC

React.createClass

React.createClass是React刚开始推荐的创建组件的方式。这是ES5的原生的JavaScript来实现的React组件。React.createClass这个方法构建一个组件“类”,它接受一个对象为参数,对象中必须声明一个render()方法,render()方法将返回一个组件实例。

先来看一个React.createClass创建组件的形式:

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.createClassmixins不够自然、直观

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.ComponentReact.createClass创建组件有蛮多不同之处,有关于这两者的区别,@toddmotto去年就写过一篇《React.createClass versus extends React.Component》,文章对两者之间做过详细的阐述。

无状态的函数写法

无状态的函数创建的组件是无状态组件,它是一种只负责展示的纯组件:

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决定,而且不会产生任何副作用。对于propsObject 类型时,我们还可以使用 ES6 的解构赋值:

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

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

这种模式被鼓励在大型项目中尽可能以简单的写法 来分割原本庞大的组件,而未来 React 也会面向这种无状态的组件进行一些专门的优化,比如避免无意义的检查或内存分配。所以建议大家尽可能在项目中使用无状态组件。

无状态组件内部其实是可以使用ref功能的,虽然不能通过this.refs访问到,但是可以通过将ref内容保存到无状态组件内部的一个本地变量中获取到。

例如下面这段代码可以使用ref来获取组件挂载到DOM中后所指向的DOM元素:

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

如何选择创建组件的方式

Facebook 官方早就声明 ES6 React.Component将取代React.createClass

剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/react/stateful-vs-stateless-components.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部