前言
上一篇文章中,我们讲到了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 操作子组件