置顶

React.js 小书

最近,在入坑react,从React.js 小书开始入门。

预览

预览
源码

JSX

const element = <h1>Hello, world!</h1>;

这种写法是不是很奇怪?包含着HTML和JavaScript。

它被称为JSX,一种 JavaScript 的语法扩展,是React 的核心组成部分。

在React 中,JSX会被编译成普通的 JavaScript 对象。举个栗子:

<ul id='list'>
  <li class='item'>Item 1</li>
  <li class='item'>Item 2</li>
  <li class='item'>Item 3</li>
</ul>

每个 DOM 元素的结构都可以用 JavaScript 的对象来表示。你会发现一个 DOM 元素包含的信息其实只有三个:标签名,属性,子元素。

所以其实上面这个 HTML 所有的信息我们都可以用合法的 JavaScript 对象来表示:

{
  tag: 'ul',
  attrs: { className: null, id: 'list'},
  children: [
    {
      tag: 'li',
      arrts: { className: 'item' }
    },
     {
      tag: 'li',
      arrts: { className: 'item' }
    },
     {
      tag: 'li',
      arrts: { className: 'item' }
    }
  ]
}

React利用render将JavaScript对象转化成DOM。主要代码如下:

Element.prototype.render = function () {
    var el = document.createElement(this.tagName) // 根据tagName构建
  var props = this.props

  for (var propName in props) { // 设置节点的DOM属性
    var propValue = props[propName]
    el.setAttribute(propName, propValue)
  }

  var children = this.children || []

  children.forEach(function (child) {
    var childEl = (child instanceof Element)
      ? child.render() // 如果子节点也是虚拟DOM,递归构建DOM节点
      : document.createTextNode(child) // 如果字符串,只构建文本节点
    el.appendChild(childEl)
  })

  return el
}

// JSX编译过程 => [过程] =>
JSX => Babel 编译 React.js =>  
JavaScript对象结构 => ReactDom.render => 
DOM元素 => 
插入页面

setState

React.js 的 state 就是用来存储这种可变化的状态的。如果要想改变某个状态呢?那就
需要setState。

setState 方法由父类 Component 所提供。setState 接受对象参数 函数参数当我们调用这个函数的时候,React.js 会更新组件的状态 state ,并且重新调用 render 方法,然后再把 render 方法所渲染的最新的内容显示到页面上。

注意:
当你调用 setState 的时候,React.js 并不会马上修改 state。

调用 setState 的时候,是把这个对象放到一个更新队列里面,稍后才会从队列当中把新的状态提取出来合并到 state 当中,然后再触发组件更新。举个栗子:

class Index extends Component {
    constructor () {
        super()
        this.state = { isLiked: false }
    }
    handleClickOnLikeButton () {
        console.log(this.state.isLiked) // false
        this.setState({
            isLiked: !this.state.isLiked
        })
        console.log(this.state.isLiked) // false
    }
    render() {
        return(
            <button onClick={this.handleClickOnLikeButton.bind(this)>
                  {this.state.isLiked ? '取消' : '点赞'} 
            </botton>
        )
    }
}

Tip:
在使用 React.js 的时候,并不需要担心多次进行 setState 会带来性能问题。// ✅

生命周期

React.js 内部对待每个组件都有一个过程,也就是初始化组件 -> 挂载到页面上的过程。

-> constructor()
-> componentWillMount()
-> render()
// 然后构造 DOM 元素插入页面
-> componentDidMount()

那么挂载的时候,执行顺序是怎样的呢?请看下面这个栗子:

class Header extends Component {
  constructor () {
    super()
    console.log('construct')
  }

  componentWillMount () {
    console.log('component will mount')
  }

  componentDidMount () {
    console.log('component did mount')
  }

  render () {
    console.log('render')
    return (
      <div>
        <h1 className='title'>React 小书</h1>
      </div>
    )
  }
}

在控制台可以看到依次输出:

construct
component will mount
render
component did mount

生命周期

componentWillMount:组件挂载开始之前,也就是在组件调用 render 方法之前调用。
componentDidMount:组件挂载完成以后,也就是 DOM 元素已经插入页面后调用。
componentWillUnmount:组件对应的 DOM 元素从页面中删除之前调用。
componentWillUnmount:组件对应的 DOM 元素从页面中删除之前调用。
componentWillUnmount: 组件销毁调用。

更新阶段

shouldComponentUpdate(nextProps, nextState):你可以通过这个方法控制组件是否重新渲染。如果返回 false 组件就不会重新渲染。这个生命周期在 React.js 性能优化上非常有用。
componentWillReceiveProps(nextProps):组件从父组件接收到新的 props 之前调用。
componentWillUpdate():组件开始重新渲染之前调用。
componentDidUpdate():组件重新渲染并且把更改变更到真实的 DOM 以后调用。

Redux

To be continued…