ReactJS教程: 开始使用Facebook的ReactJS

原文: First Look: Getting Started with Facebook’s ReactJS Library

其他React教程:

React.js入门教程

React Components

React Properties

React State

React Flux的一些理解(React Flux入门教程)

前端一般基于MVC模式, View层渲染模板到DOM. View层负责在展示数据和对用户的输入和交互做出反应. 数据存储在Model层. Model层的改变会导致View层的改变, 这一个过程由Controller层控制. 大概的模型如下图所示:

MVC图示

React 的特别之处

事实上 React 用称之为Component 的来代替了View层. Component 包括了两种对象: props (存储当创建对象实例时传递的不会变化的参数) 和 state (包括了Component当前状态, 这个状态在某些条件下是可以改变的). 总所周知, 最耗费精力的操作是对DOM的操作. React 最大的特色是当View层在渲染的时候,它不会直接从模板里面去构建一个DOM节点. 首先, 它创建一些暂时的, 虚拟的 DOM, 然后和真实的DOM还有创建的Diffs一起做对比, 然后才决定需不需要渲染. 因此React不需要开发者去操作DOM而这个过程由React来决定要不要渲染和什么时候渲染.不过不要担心, 你也可以去操作DOM, 即使React不推荐这样做. 而且 React 对 virtual DOM 的实现非常厉害, 你可以快速地去操控 DOM.

说回React最主要的Component. 你可以通过Components的结合来构建整个界面. 每一个通过render()来渲染, 并且可以层级渲染. 一个 Component树 就被建立起来了, 包括了 Component 现在的状态和任何改变之后的重新渲染的状态. 父Component 的改变也会传递到 子Component上.

因为虚拟的DOM也是Component的一部分, React提供一个类XLM,强大的扩展 - JSX. 通过这个扩展可以像XML节点一样来构建Component树. 这样在同一个文件中存储了逻辑和模板.

让我们来开始写一个ToDo List 吧. 我们的app包括了2个组件(component) - 任务列表(list 偶of tasks) 和 app 本身.

这是一个列表:

/** @jsx React.DOM */
var TodoList = React.createClass({
  render: function() {
    var createItem = function(itemText) {
      return <li>{itemText}</li>;
    };
    return <ul>{this.props.items.map(createItem)}</ul>;
  }
});

/** @jsx React.DOM */ 告知 JSX-parser 紧接着有JSX内容需要被编译.

Component只有一个方法 - render(), 这里会创建一个输入参数的列表. this.props的数据会在创建列表的过程中被传递.

var TodoApp = React.createClass({
  getInitialState: function() {
    return {items: [], text: ''};
  },
  onChange: function(e) {
    this.setState({text: e.target.value});
  },
  handleSubmit: function(e) {
    e.preventDefault();
    var nextItems = this.state.items.concat([this.state.text]);
    var nextText = '';
    this.setState({items: nextItems, text: nextText});
  },
  render: function() {
    return (
      <div>
        <h3>TODO</h3>
        <TodoList items={this.state.items} />
        <form onSubmit={this.handleSubmit}>
          <input onChange={this.onChange} value={this.state.text} />
          <button>{'Add #' + (this.state.items.length + 1)}</button>
        </form>
      </div>
    );
  }
});
React.renderComponent('<TodoApp />', document.getElementById('content'));

首先能看到一些其他的函数, 一些是内建函数一些是自定义函数.getInitialState(object)设定了组件的初始状态(state). setState(object) 改变组件的状态和使得render()被调用.在render()中我们使用<TodoList items={this.state.items} />来创建了一个任务列表.同时列表项作为参数被传递进去了.对于父组件, 列表是一个状态(states), 而对于子组件则是一个属性(props). 父组件状态的改变会导致子节点的重新渲染.

RenderComponent() 创建和渲染组件. 函数onChangehandleSubmit是根据用户输入的回调函数.React另外一个特点是时间并没有绑定到真正的DOM节点上, 而是委托到根节点上.

每一个组件在生命周期内都会传递一些状态(state)和一些特殊的回调函数. 例如一个组件被Mount(?)之前会调用componentWillMount(), 之后则会调用componentDidMount(). 这里有一些系列的时间都遵循这样的模式: componentWill* 在状态(state)改变之前被调用, componentDid* 则在之后调用. 这里还有一些列子:

  • getInitialState(): 准备组件状态
  • componentWillMount()
  • componentDidMount()
  • componentWillReceiveProps()
  • shouldComponentUpdate(): 如果你想控制跳过渲染的话很有用.
  • componentWillUpdate()
  • render()
  • componentDidUpdate()
  • componentWillUnmount()

组件的生命周期如下图所示:

组件生命周期

有一件事情必须记住的是: 数据从父到子地传递, 事件触发后从子到父地传递

数据和时间传递方式

如果在渲染后你想获得组件, 那么你需要为组件的DOM设置ref属性.

render: function(){
  // Set a ref 
  return (
    <div>
      <span ref="counter" class="count">{this.state.count}</span>
    </div>
    );
}

这样就可以通过this.refs.counter获取得到了. 为了获取实际的DOM你可以调用this.refs.counter.getDOMNode().innerHTML. 虽然这是不推荐的做法, 但是也有可能会用到.

« 返回