Component
从认识组件开始
在React
中有多种术语来描述组件,比如实例
,元素
等,那么为什么需要用这么多的方式来描述它呢?对于刚入门的你来说,你应该接触过了一些组件类。
import React,{ PropTypes } from 'react';
const propTypes = {
type: PropTypes.string
};
const defaultProps = {
type: 'checked'
};
class Icon extends React.Component {
render (){
const { type } = this.props;
return (
<i
className="icon"
/>
);
}
}
Icon.propTypes = propTypes;
Icon.defaultProps = defaultProps;
export default Icon
打个比方在你的Web应用中需要用到多个icon,那么此时在你的界面中会存在多个Icon
实例,这个实例用于呈现了icon
图标,而且它拥有着完整的特性,比如各自的props
参数以及本地的状态(state)。在编程的直观感受中,类,实例才是你真正关心的,但是对于React
它所关心只是元素
。React
本身提出了一个方式来阐述这个问题:一个元素仅仅是为纯粹的JSON对象,用来描述这个实例,组件所需要的参数以及其自实例,组件。
var element = {
type: 'div',
props: {
className: 'div-container',
children: [
{
type: 'i',
props: {
className: 'i-icon'
}
},
{
type: 'span',
props: {
className: 'text-center',
children: 'icepy'
}
}
]
}
}
这个纯粹的JSON所代表的结构如下:
<div class="div-container">
<i class="i-icon"></i>
<span class="text-center">icepy</span>
</div>
这就是React
的优势所在,这样的结构描述提高优化的几率,当你明确知晓结构中的某个点时,你可以选择跳过diff
算法的对比,直接呈现相应的片段即可。
当type不在是普通的元素
时,所需要理解的知识点稍许复杂:
var element = {
type: 'div',
props: {
className: 'div-container',
children: Icon
}
}
虽然描述改变了,但是整体的结构对象并未发生改变,进一步还原:
var element = {
type: 'div',
props: {
className: 'div-container',
children: {
$$typeof: ...,
type: 'i',
props: {
className: 'i-icon',
children: ...
}
}
}
}
这就是React的中心思想和灵感!
这样的结构非常的适合遍历,当你从type
取出元素,遇见children
往下一处开始遍历,这是非常有用的。(这让我想到了爬虫蜘蛛,在爬到网页内容时遇到a链接,问:还需要继续吗?“继续”,然后“运行”这个网页继续遇到a链接,重复之前的问题,一直到结束。)
回到React组件编写
既然是纯粹的JSON
对象描述,可以想象这里即可以使用class
(类),也可以使用function
(函数)。它们之间的区别只是在于state
,DOM的创建销毁的生命周期上,可见函数并没有类的方式提供的强大,但它往往非常的简单。
让我们看一个函数式的Hello World
例子:
function Hello (props){
const { style, children } = props;
return (
<h1
style={ style }
>
{ children }
</h1>
);
}
export default Hello
import { render } from 'react-dom'
import Hello from './hello';
render((
<Hello
style={{margin:5}}
>Hello World</Hello>
),document.getElementById('app'))
ES2015编写React组件
只需要继承React.Component
即可:
import React from 'react';
class Hello extends React.Component {
render (){
const { children } = this.props;
return (
<h1>
{ children }
</h1>
);
}
}
export default Hello;
从这里其实你应该可以明白函数和类的不同了,类拥有实例,拥有完整的React特性,你并不需要手动的new Hello()
,而是React自动帮你处理了它的实例化过程。
实现Header
效果图:
类似navigation
的动态效果,我认为在实现一个组件之前应该有一个基础的分析过程,它存在着左中右,这样的基础结构,如果你实在分析不出来,我推荐你先写一个普通的对象描述一下:
var element = {
type: 'div',
props: {
children: [
{
type: 'div',
className: 'div-left',
props: {
...
}
},
{
type: 'div',
className: 'div-center',
props: {
...
}
},
{
type: 'div',
className: 'div-right',
props: {
...
}
}
]
}
}
可能存在这样的数据:
var props = {
title: '',
leftItem: {
icon:'',
text:''
},
rightItem:[
{
icon: '',
text: ''
}
],
tags:[
{
active: '',
text: ''
}
],
complex:[
{
type: '',
text: ''
}
]
}
定义数据(props)
const propTypes = {
title: PropTypes.string,
modal: PropTypes.string,
tags: PropTypes.array,
complex: PropTypes.array,
leftItem: PropTypes.object,
rightItem: PropTypes.array
}
const defaultProps = {
title: '', //标题
tags: [], // 选项标题
complex: [], //复合标题
modal: 'normal', //mutil
leftItem: {
icon: 'v-left',
text: '',
methods: {}
},
rightItem: [
{
idx: '1',
icon: 'dots',
text: '',
methods: {}
}
]
}
定义根组件
import React, { PropTypes } from 'react';
import classNames from 'classnames';
import Selector from './Selector';
import LeftItem from './LeftItem';
import RightItem from './RightItem';
class Header extends React.Component {
render (){
const { leftItem, style, rightItem } = this.props;
const { methods } = leftItem;
return (
<header
style={ style }
className="header"
>
<div
{...methods}
className="header-left"
>
<LeftItem leftItem={ leftItem }/>
</div>
<div className="header-right">
{ RightItem(rightItem) }
</div>
<Selector {...this.props} />
</header>
);
}
}
Header.propTypes = propTypes;
Header.defaultProps = defaultProps;
export default Header;
在这里可以将不同类型的Header
进行分离,我们知道函数仅仅是不够强大,但也可以使用,大家可以看到LeftItem
用于定义左边的按钮。
import Icon from '../icon/'
function LeftItem (props){
const { leftItem } = props;
const { icon, text } = leftItem;
if (icon) {
return (
<Icon
value={ icon }
className="header-icon js-back"
/>
);
} else {
if (text) {
return (
<span
className="header-btn"
>
{ text }
</span>
);
} else {
return (
<span className="header-mix">
<Icon
value={ icon }
/>
<span className="mix-txt">
{ text }
</span>
</span>
);
}
}
return null;
}
export default LeftItem;
是不是其实没有想象中的那么困难?