React 是 21 世纪人类智慧的结晶。

目前几乎绝大部分的组件化方案都是基于 React 实现,因为 React 就是专门为组件化而生的。因此,ICE 后台解决方案也采用了 React 这套方案进行构建。

了解 React

本文档不只谈 React 的功能、特性、优势,而是按照实际业务需求对创建一个 React 组件流程做一个介绍,并附带介绍相关特性给出详细参考文档链接。

创建一个 React 组件

首先拿到一系列的页面,我们第一步并不是去马上开发,而是先观察可复用部分抽出成独立的小组件,然后就可以通过拼接组件组装页面了。

制作一个组件通常需要展示一段 HTML 代码,创建一个最简单的 React 方法如下:

  1. class HelloMessage extends React.Component {
  2. render() {
  3. return (
  4. <div>Hello world!</div>
  5. );
  6. }
  7. }

只需要声明一个继承 React Component 的 class 即可创建一个组件,每个组件必须要有一个 render 方法,render 方法的返回值是一段 JSX 代码。

JSX 语法跟 HTML 很像,但是还是有一些不同,比较简单的场景下,你可以看做是一样的。JSX 具体语法请参见这篇文档

创建了一个 class 我们还需要去实例化、执行才可以渲染到页面上,所以我们可以调用下面这句代码将这个组件实际的渲染出来:

  1. ReactDOM.render(<HelloMessage />, document.body);

为 React 组件传入数据

组件往往是需要展示一些动态数据的,而不是静态的,因此内容不能写死需要获取并传递下去。为此 React 创建了 props 这个概念用来往组件传入数据。

  1. class HelloMessage extends React.Component {
  2. render() {
  3. return (
  4. <div>Hello {this.props.name}</div>
  5. );
  6. }
  7. }
  8. ReactDOM.render(<HelloMessage name="浩睿" />, mountNode);

渲染组件的时候,按照 HTML 的方式传递一个属性 name 和值 ‘浩睿’,即可在组件内部的任何位置使用 this.props.name 拿到这个值进行处理。

props 是只读的,用来获取上层组件传递下来的数据。详情请参见:http://stackoverflow.com/questions/27991366/what-is-the-difference-between-state-and-props-in-react

React 组件的变化是基于状态的

如果设计一个灯开关组件,那么对于这个开关组件它有两种状态,一种是开关开启状态(此时需要连通电线),一种是开关关闭状态(此时需要断开电线),而摁下开关是则是一种触发行为。为此 React 创建了 state 这个概念用来描述组件内部的状态,并支持获取事件进行触发。

  1. class Switch extends React.Component {
  2. state = {
  3. // 开关状态默认关闭
  4. switchStatus: false
  5. }
  6. switch = () => {
  7. // 切换开关的值
  8. this.setState({
  9. switchStatus: !this.state.switchStatus
  10. });
  11. };
  12. render() {
  13. if (this.state.switchStatus) {
  14. return (
  15. <div>
  16. <h1>灯已经打开,电线接通</h1>
  17. <button onClick={this.switch}>关灯</button>
  18. </div>
  19. );
  20. } else {
  21. return (
  22. <div>
  23. <h1>灯已经关闭,电线断开</h1>
  24. <button onClick={this.switch}>开灯</button>
  25. </div>
  26. );
  27. }
  28. }
  29. }

组件内用到的数据都算作一种状态,存储在 state 里面,当可以拦截某些行为来去改变 state 的值(比如 点击 按钮),需要注意的是改变当前组件的 state 不能直接用 this.state.switchStatus = true 来改,必须使用 this.setState 方法进行修改。原因是因为状态改变了之后,React 需要重新执行 render 方法进行渲染,此时 render 方法读取 this.state.switchStatus 的值就是最新的数据,渲染结果也是最新的。所以必须有一种机制通知 React state 已经变换了,直接改变 this.state.switchStatus = true 的值,React 无法检测到状态有変更,因此必须使用 this.setState({xxx}) 来修改 state 值。

React 组件在渲染的时候需要遵循一定的执行顺序,比如 state 改变之后必须重新执行 render 方法等。为了方便控制 React 的执行顺序和流程,React 创建了生命周期的概念用来处理此类功能。

关于 props 和 state 的详解,请参见:http://stackoverflow.com/questions/27991366/what-is-the-difference-between-state-and-props-in-react

React 组件的生命周期

就像一个人一样,出生、赋予属性(props)、成长(state 変更)、衰老死亡(组件销毁),React 组件同样存在这些状态,便于做相关功能处理。

  1. class Person extends React.Component {
  2. // 即将出生(刚开始调用)
  3. componentWillMount() {
  4. console.log('我要出生了,我的名字叫 ', this.props.name);
  5. }
  6. // 出生(开始渲染,准备初始数据,调用 render 方法)
  7. constructor(props) {
  8. super(props);
  9. console.log('name', this.props.name);
  10. this.state = {
  11. name: this.props.name,
  12. age: 0
  13. };
  14. // 时间开始转动,5 秒等于 1 岁
  15. this.timer = setInterval(() => {
  16. this.setState({
  17. age: this.state.age + 1
  18. });
  19. }, 5000);
  20. console.log('我正在出生');
  21. }
  22. // 出生完毕(调用 render 完成并渲染到页面上)
  23. componentDidMount() {
  24. console.log('我已经出生');
  25. }
  26. // 接收了新的属性
  27. componentWillReceiveProps(nextProps) {
  28. // 换了个新名字,固定的属性
  29. if (nextProps.name !== this.state.name) {
  30. console.log('我换了个名字:', nextProps.name);
  31. this.setState({
  32. name: nextProps.name
  33. });
  34. }
  35. }
  36. // 要重新渲染了(准备过生日)
  37. componentWillUpdate() {
  38. console.log('我要改变了!');
  39. }
  40. // 更新渲染完成了(过完生日)
  41. componentDidUpdate() {
  42. console.log('我改变完了!');
  43. }
  44. // 要火化了(组件销毁)
  45. componentWillUnmount() {
  46. // 停止时间
  47. console.log('再见啦!');
  48. clearInterval(this.timer);
  49. }
  50. render() {
  51. console.log('我正在改变!');
  52. return (
  53. <div>
  54. <h1>姓名:{this.state.name},年龄:{this.state.age}</h1>
  55. </div>
  56. );
  57. }
  58. }

每一次 props 或者 state 改变,都会重新渲染组件,为了阻止渲染,React 还提供了 shouldComponentUpdate 方法,在 render 前判断是否有必要执行 render 提升性能。关于 React 声明周期,详情请参见官方文档:https://facebook.github.io/react/docs/react-component.html

附生命周期图:

lifecycle

总结

至此,几大 React 特性你大概了解了,再来回顾一下:

  • props 用来传递数据,state 用来存储组件内部的状态和数据。props 是只读的,state 当前组件 state 的值可以作为 props 传递给下层组件。
  • React 组件按照生命周期运行,改变 state 就会重新执行 render 方法。render 方法返回的是一段 JSX 语法的结构用来渲染到页面上。