前言

上一篇文章中,我们讲到了JSX的一些用法和注意事项,这次我们来讲react中最基础也是特别重要的内容:组件。这篇文章包含组件的以下内容:状态、属性、生命周期。

正文

一.组件演变

W3C标准委员会制定的规范:Web Components.每个自定义组件可以定义自己对外提供的属性、方法、还有事件。,内部可以像写一个页面一样,专注于实现功能来完成对组件的封装。
1.Web Components主要由四部分组成
(1)HTML templates 定义了之前模板的概念
(2)Custom Elements 定义了组件的展现形式
(3)shadow DOM 定义了组件的作用域范围、可以囊括样式
(4)HTML Imports 提出了新的引入方式
图片描述

二.React组件的构建

React的本质就是关心元素的构成,React组件即为组件元素。组件元素被描述为纯粹的JSON对象,意味着可以使用方法和类来构建。React组件基本上有三部分组成: 属性、状态和生命周期方法。

图片描述

React组件可以接收参数,也可能有自身状态。一旦接收到的参数或者自身状态有所改变,React组件就会执行相应的生命周期方法,最后渲染。

React组件的构建方法
(1)React.createClass
用React.createClass构建组件是最传统、兼容性最好的方法。
示例代码如下:

const Button = React.createClass({
    getDefaultProps(){
        return{
            color:'blue',
            text:'confirm'
        };
    },
    render(){
        const {color,text} = this.props;
        return(
            <button className={'btn btn-${color}'}>
                <em>{text}</em>
            </button>
        );
    }    
});

(2)ES6 Classes

import React,{Component} from 'react'

class Button extends Component{
constructor(props){
    super(props);
}
static defaultProps = {
    color:'blue',
    text:'confirm'
}
render(){
    return (
    <button className={'btn btn-${color}'}>
        <em>{text}</em>
    </button>
    );
}

}

(3)无状态组件
使用无状态函数构建的组件就称为无状态组件。
示例代码如下:

function Button({
    color:'blue',
    text:'confirm'
}){
    return (
        <button className = {'btn btn-${color}'}>
            <em>{text}</em>
        </button>
    );
};

注意事项:
(1)无状态组件只传入props和context两个参数;也就是说它不存在state,也没有生命周期方法。
(2)无状态组件不会像上面两种方法一样在调用时会创建新的实例,它创建时始终保持了一个实例。

三.React数据流

1.简单介绍:
(1)在React中,数据是自顶向下单向流动,即从父组件到子组件。
(2)如果顶层组件初始化 props,那么React会向下遍历整棵组件树,重新尝试渲染所有相关的子组件。
(3)而state只关心每个组件自己内部的状态,这些状态只能在组件内变化。

2.state
每一个组件都有自己的state,它存在于组件的内部。
当组件内部使用库内置的setSate方法时,最大的表现行为就是该组件会尝试重新渲染。
值的注意的是,setState是一个异步方法,一个生命周期内的所有setSate方法会合并操作。

3.prop
props是properties的简写,它是react用来组件间联系的一种机制,通俗地讲就像方法的参数一样。
React的单向数据流主要的流动通道就是prop。prop本身是不可变的。组件的props一定来自默认属性或通过父组件传递而来。react为props提供了默认配置,通过defaultProps静态变量的方式定义。

子组件prop:
在React中有一个重要的内置 Prop——children,它代表组件的子组件集合。React.Children是官方提供的一系列操作children的方法。它提供诸如:map forEach count等使用函数,可以为我们处理子组件提供便利。

propTypes:
propTypes用于规范props的类型与必需的状态。如果组件定义了propTypes,那么在开发环境下就会对组件的props值进行类型检查,如果不匹配,就会在控制台里报warning.

4.prop与state的区别
本标题下内容来源:https://github.com/yunxifd/re...

官方文档中已经给出了怎样判断数据是否应为组件的state的方法:
1、数据是否从父组件通过props传递给子组件?如果是,它可能不是state。
2、数据是否随着时间的推移不发生变化?如果是,它可能不是state。
3、数据是否能够通过其他state或props计算所得?如果是,它就不是state。

进一步探索,参考文档Working with Data in React: Properties & State

props 是组件的输入值,主要用来初始化组件的state和渲染组件。实例化组件后,props是不可变的。props只能在组件实例化的时候,设置值。因此,当组件re-rendered的时候,react会比较new和old props 来决定哪些DOM需要更新。

state 表示由组件更改的数据,通常是通过与用户的交互来更改的。为了实现state的修改,需要注册事件处理程序到相应的DOM元素上。当事件发生时,将更新后的值是从DOM中检索,并通知组件。在组件可以使用state,组件必须通过getInitialState函数初始化。通常情况下,该getInitialState函数初始化状态使用static value,props,或其他数据存储。

总结:
props 是不可变的
state 是可变的

四.组件生命周期

图片描述

1.组件的挂载

import React,{Component,PropTypes} from 'react'
class App extends React.Component{
    static propTypes{
        //...
    };
    static defaultProps={
        //...
    };
    constructor(props){
        super(props);
        this.state={
            //...
        };
    }
    componentWillMount(){
        //...
    }
    componentDidMount(){
        //...
    }
    render(){
        <div>this is a demo </div>
    }
}

getDefaultProps:
对于组件类来说,这个方法只会被调用一次。对于那些没有被父辈指定props属性的新建实例来说,这个方法返回的对象可用于为实例设置默认的props值

getInitialState:
对于组件的每个实例来说,这个方法的调用次数有且只有一次。在这里你有机会初始化每一个实例的state。与getDefaultProps不同的是,每次实例创建时,该方法都会调用一次。在这个方法里,你已经可以访问到 this.props

componentWillMount:
该方法会在首次渲染之前被调用,这也是在render方法调用前可以修改组件state的最后一次机会。

render:
在这里你会创建一个虚拟的DOM,用于表示组件的输出。对于一个组件来说, render是唯一一个必须的方法。
render方法返回的结果不是真正的DOM,而是一个虚拟的表现,react随后会和它真是的DOM做对比,来判断是否有必要做出修改。

componentDidMount:
在render方法成功调用并且真是的DOM已经被渲染之后,你可以在componentDidMount内部通过this.getDOMNode()方法访问到它。

2.组件的卸载

componentWillUnmount:
该方法会在组件移除之前被调用,让你有机会做一些清理工作。我们常执行一些清理方法,比如事件回收或者清除定时器。

3.数据更新过程

数据更新指的是父组件向下传递props或许组件自身执行setState方法时发生的一系列更新动作。

class App extends React.Component{
    componentWillReceiveProps(nextProps){
        //this.setSate({})
    }
    shouldComponentUpdate(nextProps,nextSate){
        //return true
    }
    componentWillupdate(preProps,preSate){
        //...
    }
    componentDidUpdate(){
        //...
    }
    render(){
        return(
            <div>this is a demo </div>
        )
    }
}

componentWillReceiveProps:
在任意时刻,组件的props都可以通过父辈组件来更改。出现这种情况时,该方法将会被调用,它也将获得更改props对象以及更新state的机会。

shouldComponentUpdate:
它接收需要更新的prop和state,让开发者增加必要的条件判断,让其在需要时更新,不需要时不更新。因此,当该方法返回false的时候,组件不在向下执行生命周期方法。

componentWillUpdate:
组件会接收新的props和state进行渲染之前调用该方法。
注意:你不可以在该方法中更新props和state。而应该借助componentWillReceiveProps在运行时更新
state.

componentDidUpdate:
该方法给我们提供了更新已经渲染好的DOM的机会。

五.组件设计原则

详细请见:https://github.com/react-comp...
(1)职责清晰
多个组件协同完成一件事情,而不是一个组件替其他组件完成本该它自己完成的事情。
(2)扁平访问
组件推荐使用状态来控制交互和显示,如果需要显示访问,也尽量实行扁平访问,即只可以调用其 children 的方法。
(3)信息冗余
尽量避免信息冗余,如果某个 state 可以由其他 state 计算得到,那么就删除这个 state
(4)api 尽量和已知概念保持一致
如果 api 可以和已知概念保持一致,那么就用已知的 api
(5)使用标签嵌套
尽量使用标签嵌套而不是属性配置。
(6)避免使用 ref
使用父组件的 state 控制子组件的状态而不是直接通过 ref 操作子组件


specialcoder
2.2k 声望170 粉丝

前端 设计 摄影 文学