React入门实例

什么是React?

官方网站的第一句话:A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES. 用于构建用户界面的Javascript库。

React为应用提供也仅仅提供视图层(UI)的解决方案,通过几个简单示例,我们可以对React有个初步的了解。示例位于代码库learning-reactprimer下。

01 你好, 世界

在线演示

React允许在Javascript代码中嵌入HTML标签,通过ReactDOM.render方法,将模板转化为HTML并插入指定的DOM节点。

ReactDOM.render(
  <h1>hello, world</h1>,
  document.body
);

注意:

  • <script type="text/babel">是为了兼容JSX语法(就是将HTML嵌入Javascript这种方式)。
  • 引入browser.min.js将JSX语法转化为Javascript语法,实际上线应该在服务器完成转换以节省时间。

02 组件和JSX语法

在线演示

组件即代码和功能的集合,可以像使用HTML标签一样使用组件。通过React.createClass方法生成组件类。

下面的代码UI展现了水果组件(Fruits),水果组件又引入了价格组件(PirceList)。

var Fruits = React.createClass({
  render: function() {
    return <div>
      <h1>Fruit</h1>
      <PriceList />
    </div>;
  }
});
var PriceList = React.createClass({
  render: function() {
    ...
  }
});
ReactDOM.render(
  <Fruits />,
  document.body
)

JSX允许HTML与Javascript代码混写,当遇到<时解析为HTML,当遇到{时解析为Javascript。

注意:

  • 组件类的第一个字母必须大写。
  • 所有组件必须有render方法。
  • 组件return只能包含一个顶层标签。
  • 组件return与标签左尖括号必须在同一行,为了代码美观可以用圆括号包一层。
  • JSX输出Javascript变量时,如果变量是数组,会自动展开。

03 props和state

在线演示

组件的UI展现由两个数据决定,初始化后不变的数据this.props和随着用户交互改变的数据this.stategetDefaultProps方法和getInitialState方法分别用来初始化默认的propsstate

下面的代码中,标语(banner)是组件初始化之后不应该再改变的内容,而水果价格的隐藏与否是随用户的交互而变化的。setState方法修改状态值,然后自动调用render方法重新渲染UI。

getDefaultProps: function() {
  return {banner: 'Default banner: Welcome'};
},
getInitialState: function() {
  return {hide: false};
},
onClick: function(e) {
  this.setState({hide: !this.state.hide});
},
render: function() {
  var fruit = {name: 'apple', price: 6888};
  return (
    <div>
      <h1>{this.props.banner}</h1>
      <p>{fruit.name} {this.state.hide ? '--' : '¥' + fruit.price}</p>
      <button onClick={this.onClick}>{this.state.hide ? 'show price' : 'hide price'}</button>
    </div>
  )
}

知道组件的state,就知道组件渲染出来的样子,不用再一步步跟踪程序流程,这在团队开发中是非常重要和具有优势的。

注意:

  • 直接改变this.state并不会重新渲染。(类似这样: this.state.hide = true)
  • 传入的props会覆盖默认的props

04 组件的生命周期

在线演示

组件的状态分为挂载(Mount)、更新(Update)和移除(Unmount),相应的有以下五个方法:

componentWillMount()

仅调用一次,在初始化渲染之前执行,此时调用setState方法并不会引起二次渲染。

componentDidMount()

仅调用一次,在初始化渲染之后执行,可以在这个阶段设置定时器或发送AJAX请求。可以通过this.refs获取到真实的DOM节点。

componentWillReceiveProps(object nextProps)

接收到新的props时调用,此时调用setState不会引起二次渲染。

shouldComponentUpdate(object nextProps, object nextState)

在接收到新的props或state时执行,决定是否需要更新组件,默认返回true。如果返回false,componentWillUpdatecomponentDidUpdaterender都不会执行。初始化渲染和执行forceUpdate时,该方法不会调用。

componentWillUpdate(object nextProps, object nextState)

当获取到新的props或state的时候执行,初始化渲染的时候不执行。nextPropsnextState是新获取的数据,此时可以通过this.propsthis.state获取到老的值。

componentDidUpdate(object prevProps, object prevState)

更新已经同步到DOM后执行,初始化渲染的时候不执行。

componentWillUnmount()

组件从DOM移除时执行,可以在这个阶段执行必要的清理,比如无效的定时器。

var PriceList = React.createClass({
  componentWillMount: function() {
    this.setState({name: 'apple', price: 6888});
  },
  componentDidMount: function() {
    this.timer = setInterval(this.cheap, 1000);
  },
  componentWillUnmount: function() {
    clearInterval(this.timer);
  },
  cheap: function() {
    this.setState({price: this.state.price - 100});
  },
  render: function() {
    return <h3>{this.state.name} {this.state.price}</h3>;
  }
});
ReactDOM.render(
  <PriceList />,
  document.body
);

更多生命周期相关方法参见官方文档

注意:

  • 不要在componentWillUpdate方法中调用setState,可能会造成无限循环。

05 表单

在线演示

在React中,涉及用户交互的表单组件(input、checkbox等),如果设置了默认值(value、checked等),那么它是一个受限组件,受限组件将始终渲染它的默认值。

下面代码中input就是一个受限组件,用户输入无法改变它的渲染。

<input type="text" value="can not change me" />

有两种方式可以改变这一现状:

  1. 使用特有属性

    对于input、select使用defaultValue属性,对于checkbox、radio使用defaultChecked属性。

    <input type="text" defaultValue="change me" />
    
  2. 使用事件监听

    在表单组件中监听值的改变,然后更新表单当前值。

    handleChange: function(event) {
      this.setState({text: event.target.value});
    )
    
    <input type="text" value={this.state.text} onChange={this.handleChange} />
    

详细请查看表单事件