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;

是不是其实没有想象中的那么困难?

results matching ""

    No results matching ""