1.3 React 组件
1.3.1 React 组件引见
在 React 中组件是第一元素,是 React 的基本,一个 React 运用就是基于 React 组件的组合而成。
前面的 JSX 演习事后,人人应当对 React 组件不陌生了,在这一节我们将复习以及深切进修 React 组件。
1.3.2 建立一个 React 组件
建立一个 React 组件的要领为,挪用 React.createClass 要领,传入的参数为一个对象,对象必需定义一个 render 要领,render 要领返回值为组件的衬着构造,也可以理解为一个组件实例(React.createElement 工场要领的返回值),返回值有且只能为一个组件实例,或许返回 null/false,当返回值为 null/false 的时刻,React 内部经由历程 <noscript/> 标签替代。
eg:
var MyComponent = React.createClass({
render: function() {
return <p>....</p>;
}
});
组件定名空间
可以看出 React.createClass 天生的组件类为一个 Javascript 对象。 当我们想设置定名空间组件时,可以在组件下面增添子组件:
eg:
MyComponent.SubComponent = React.createClass({...});
MyComponent.SubComponent.Sub = React.createClass({....});
在组件较多的情况下,可以借助定名空间优化组件保护构造以及处理组件称号争执题目。
无状况组件
除了可以经由历程 React.createClass 来建立组件之外,组件也可以经由历程一个一般的函数定义,函数的返回值为组件衬着的效果。
eg:
function StatelessComponent(props) {
return <div> Hello {props.name} </div>
}
无状况组件可以优化机能,由于其内部不会保护状况,React 内部不会有一个对应的组件实例,而且也没有生命周期 hook。
1.3.3 将组件衬着到 DOM 中
当建立好了组件事后,为了将组件衬着到 DOM 中显示出来,须要两个步骤
在 HTML 中定义一个元素,设置 id 属性
JSX 中挪用 ReactDOM.render 要领, 第一个参数为 组件,第二个为适才定义的 DOM 元素
eg:
<!-- 定义的 DOM 元素 -->
<div id="example"></div>
<script type="text/babel">
// 自定义组件
var MyComponent = React.createClass({
render: function() {
return <p>....</p>;
}
});
// 挪用 render 要领
ReactDOM.render(
<MyComponent/>,
document.getElementById('example')
);
</script>
关于组件的衬着,能够涉及到的一些题目:
Q1: 只能 render 到一个元素吗?
Q2: 在顺序运行时可以动态的挪用 render 吗?
Q3: 修正了数据事后,还须要从新挪用 render 要领吗?
这里要先提一下 React 的设想初志,React 在开辟时刻的目的就是简朴精致,可以和其他框架结合起来运用。简朴而言我们可以当 React 是一个衬着数据对象到 DOM 中的 Javascript 函数东西类,东西类固然可以屡次运用。
那末关于上面的题目:
A1: 不是,React 可以衬着到多个元素,恣意位置的元素。
A2: 可以,比方以一个弹出层组件为例,我们愿望建立一个 append 到 body 末了的组件来完成全屏遮罩, 那末我们可以动态的建立一个 div append 到 body 末了,然后将弹出层 render 到谁人 div 内。
A3: 假定每次数据转变都从新挪用 render 要领,那末每次 render 带来的效果是从新建立一个顶级组件实例,以及子组件实例。 假如只挪用 render 一次,将数据的变动放在组件内部,那末就不会反复建立顶级组件。
1.3.4 组件状况 State
React 中每一个组件可以存储本身的当前状况, 以一个 switch 开关组件为例,开关的状况可以存储在组件内部。
React 的衬着效果是由组件属性和状况配合决议的,状况和属性的区别是,状况保护在组件内部,属性是由外部掌握,我们先引见组件状况相干细节:
掌握状况的 API 为:
this.state:组件的当前状况
getInitialState:猎取组件的初始状况,在组件加载的时刻会被挪用一次,返回值给予 this.state 作为初始值
this.setState:
组件状况转变时,可以经由历程 this.setState 修正状况
setState 要领支撑按需修正,如 state 有两个字段,仅当 setState 传入的对象包含字段 key 才会修正属性
每次挪用 setState 会致使重衬着挪用 render 要领
直接修正 state 不会重衬着组件
eg:
var Switch = React.createClass({
// 定义组件的初始状况,初始为关
getInitialState: function() {
return {
open: false
}
},
// 经由历程 this.state 猎取当前状况
render: function() {
console.log('render switch component');
var open = this.state.open;
return <label className="switch">
<input type="checkbox" checked={open}/>
</label>
},
// 经由历程 setState 修正组件状况
// setState 事后会 React 会挪用 render 要领重衬着
toggleSwitch: function() {
var open = this.state.open;
this.setState({
open: !open
});
}
})
1.3.5 组件属性 Props
前面已提到过 React 组件可以通报属性给组件,通报要领和 HTML 中无异, 可以经由历程 this.props 猎取组件属性
属性相干的 API 为:
this.props: 猎取属性值
getDefaultProps: 猎取默许属性对象,会被挪用一次,当组件类建立的时刻就会被挪用,返回值会被缓存起来,当组件被实例化事后假如传入的属性没有值,会返回默许属性值
this.props.children:子节点属性
propTypes: 属性范例搜检
以一个代办事项的列表项组件为例:
// props.name 示意代办事项的称号
var TodoItem = React.createClass({
render: function() {
var props = this.props;
return <div className="todo-item">
<span className="todo-item__name">{props.name}</span>
</div>
}
});
ReactDOM.render(
<TodoItem name="代办事项1"/>,
document.getElementById('example'));
children 属性
组件属性中会有一个特别属性 children ,示意子组件, 照样以上面一个组件为例子,我们可以换一种体式格局定义 name:
var TodoItem = React.createClass({
render: function() {
var props = this.props;
return <div className="todo-item">
<span class="todo-item__name">{props.children}</span>
</div>
}
});
ReactDOM.render(
<TodoItem>代办事项1</TodoItem>,
document.getElementById('example'));
须要注重的是,children 只能为一个元素,不能为多个组件
属性范例搜检
为了保证组件通报属性的正确性, 我们可以经由历程定义 propsType 对象来完成对组件属性的严厉校验:
var MyComponent = React.createClass({
propTypes: {
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 任何可以被衬着的包含,数字,字符串,组件,或许数组
optionalNode: React.PropTypes.node,
// React 元素
optionalElement: React.PropTypes.element,
// 罗列
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
// 恣意一种范例
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
// 细致范例的数组
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
// 细致范例的对象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
// 相符定义的对象
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
requiredFunc: React.PropTypes.func.isRequired,
requiredAny: React.PropTypes.any.isRequired,
// 自定义校验
customProp: function(props, propName, componentName) {}
}
});
属性通报的单向性
我们已提到过 React 的单向数据流形式,数据的活动管道就是 props,活动的方向就是组件的层级自定向下的方向。所以一个组件是不能修正本身的属性的,组件的属性一定是经由历程父组件通报而来(或许默许属性)。
无状况组件属性
关于无状况组件,可以增添 .propTypes 和 .defaultProps 属性到函数上。
1.3.6 组件的嵌套组合
在 1.2 节的 JSX 实例子中,当我们轮回输出 todo 列表的时刻,React 会提醒关于轮回输出的组件,须要有一个唯一的 key 属性。这个题目的缘由在于 React 的折衷机制(Reconciliation)上。
什么叫折衷?
在每次数据更新事后,React 会从新挪用 render 衬着出新的组件构造,新的构造运用到 DOM 中的历程就叫做折衷历程。
为何须要折衷?
想想,假定我们有一个输入组件,这个时刻我们正聚焦在输入框中,当修正值事后触发事宜致使了数据转变,数据转变致使了重衬着, 这个时刻输入框被替代成了新的 DOM。 这个历程对用户来讲应当是无感知的,所以那本来的聚焦状况应当被保留, 那怎样做到的呢? DOM 都被替代了,输入状况,挑选状况为何还能保留。 我们先不急着晓得 How,现在只须要晓得这就是折衷历程,背面我们会在 React 完成道理章节举行细致引见。
除了保留状况之外,折衷历程还做了许多 DOM 优化。 比方输出一个数组的时刻,数据新增添或许减少了一下,或许数组项值转变了,实际上我们没有必要删除本来的 DOM 构造,只须要修正 DOM 的值或许删除 DOM 就可以完成重衬着。
这就是为何要有 key 属性,key 属性可以协助定位 DOM 与数组元素的关联,在重衬着的时刻可以完成衬着优化。
1.3.7 实例演习:经由历程组件化的体式格局优化之前的待办事项列表
题目
优化 JSX 语法演习的 TODOMVC 页面, 经由历程组件化的体式格局拆分页面!
组件以下:
App 组件:全部页面的最完成组件
Header 组件:头部输入组件
TodoList 组件:列表组件
TodoItem 组件: 列表项
Footer 组件:底部操纵组件
Tips
轮回输出组件的体式格局
体式格局一:先盘算出组件
function render() {
var todos = this.props.todos;
var $todos = todos.map(function(todo) {
return <Todo data={todo}/>
});
return <div>
{$todos}
</div>
}
体式格局二:{} 内直接盘算
function render() {
var todos = this.props.todos;
return <div>
{todos.map(function(todo) {
return <Todo data={todo}/>
})}
</div>
}