2

一 学习方式

学一门新技术,我习惯的学习方式是:

  1. 首先,先1-2遍官方文档。每个方法api都过一遍,有个大概的印象,记录下当时没懂的问题。
  2. 然后,根据文档中例子,实际动手自己去做一遍
  3. 接着,去分析项目里的代码,找一个有代表性的页面,分析这个页面的code,结合官方文档api,查漏补缺模糊、不懂的知识点。
  4. 之后,再笼统的大概分析下其他页面的代码,记录下问题,带着疑问再倒回去把官方api重头到尾再过两遍。

二 学习资源

阶段 学习目标 文档资源 参考资源
1. 基础准备 es6
babel
yarn
http://es6.ruanyifeng.com/ http://kangax.github.io/compa...
http://www.ruanyifeng.com/blo...
2. 技术文档 react
https://doc.react-china.org/d... (中文翻译)
https://reactjs.org/docs/hell... (英文原版
https://github.com/reactnativ... ( React-Native学习指南)——推荐
http://www.ruanyifeng.com/blo... (阮一峰的demo教程,虽然比较老了,但逻辑思路很清晰)
http://blog.csdn.net/mafan121... (react生命周期)
jsx语法 https://doc.react-china.org/d...
React-router http://react-guide.github.io/... http://www.ruanyifeng.com/blo...
https://github.com/reactjs/re...
https://github.com/ReactTrain...
Redux
React-redux
http://www.redux.org.cn/docs/... 教程一
教程二
教程三
Ant Design https://ant.design/docs/react...
脚手架 dva-cli
create-react-app
https://github.com/dvajs/dva-cli
https://github.com/facebook/c...
(用官方的脚手架很容易上手,整体感知一个项目,会用基本的操作就好。)
Axios https://www.npmjs.com/package...
https://www.kancloud.cn/yunye... (中文文档)
3.深入

利用react + react-router + react-redux + antd + yarn 完成了一个 todo-demo,地址:https://github.com/ranyingxia...

三 学习笔记

react 生命周期

react生命周期
React严格定义了组件的生命周期会经历如下三个过程:

装载过程(Mount),组件第一次在DOM树渲染的过程。
更新过程(Update),当组件被重新渲染的过程。
卸载过程(Unmount),组件重DOM树中删除的过程。

装载过程,依次会调用以下函数:

constructor():ES6类的构造函数(为了初始化state或绑定this)
getInitialState():ES5中初始化state。
getDefaultProps():ES5中初始化props。在ES6中使用defaultProps()方法。
componentWillMount():在组件被挂载前调用。只执行一次。
render():渲染组件,必须实现该方法。
componentDidMount():在组件装载后调用。这时已经生成了真实的DOM节点。只执行一次。

更新过程, 当组件的props或者state改变时就会触发组件的更新过程,依次会调用如下函数:

componentWillReceiveProps(nextProps):当父组件的render()方法执行后就会触发该方法。初始化时不调用。
shouldComponentUpdate(nextProps,nextState):当props改变或state改变时调用,初始化时不掉用,返回boolean。true表示继续执行render方法,fasle表示放弃本次渲染。
render():渲染组件。

卸载过程:

componentWillUnmount():将组件从DOM树移出,防止内存溢出

React中的受控组件和非受控组件

1.受控组件:受控组件
一个受控的<input>组件都有一个value属性。渲染一个受控的<input>会展示出value属性的值。
一个受控的组件不会维护它自己内部的状态,组件的渲染单纯的依赖于props。

非受控组件的输入框类似于传统的表单输入,可以使用一个ref来获取它的值。例如,一个按钮的onClick操作:

class Form extends Component {
  handleSubmitClick = () => {
    const name = this._name.value;
  }
  render() {
    return  (
      <div>
        <input type="text" ref={input => this._name = input} />
        <button onClick={this.handleSubmitClick}>Sign up</button>
      </div>
    );
  }
}

2.非受控组件:非受控组件
一个没有value属性的<input>就是一个非受控组件。通过渲染的元素,任意的用户输入都会被立即反映出来。
一个非受控的组件自己维护自己的state。

class From extends Component {
  constructor(){
    super();
    this.state = {
      name: ''
    }
  }
  handleNameChange = (event) => {
    this.setState({name: event.target.value })
  }
  render(){
    return (
      <div>
        <input
          type="text"
          value={this.state.name}
          onChange={this.handleNameChange}
        />
      </div>
    );
  }
}

每次键入了一个新的字符,就会调用handleNameChange。它会获取input最新的值并在state中设置

开始设置值为空字符串—''
你输入一个a,然后执行handleNameChange获得a并且设置了setState,然后input输入框a被重新渲染
你继续键入b,handleNameChange获得ab并且设置state,input输入框再次被重新渲染,现在的值是value=ab

这种“推入式”的流程改变了表单控件,因此表单控件总是能够一直获取输入框当前的值,而不用明确知道对象是谁。这意味着你的数据state以及UIinput总是异步的。状态将值赋給输入框,输入框通知表单改变当前的值
原文请查看:https://goshakkk.name/control...

React创建组件的三种方式以及区别

目前创建组件的方式大概有3中:

函数式定义的无状态组件
es5原生方式React.createClass定义的组件
es6形式的extends React.Component定义的组件

这三种创建方式如何选择?结论是:
只要有可能,尽量使用无状态组件创建形式。能用React.Component创建的组件的就尽量不用React.createClass形式创建组件,

function HelloComponent(props, /* context */) { return <div>Hello {props.name}</div> } ReactDOM.render(<HelloComponent name="Sebastian" />, mountNode)

无状态函数式组件形式上表现为一个只带有一个render方法的组件类,通过函数形式或者ES6 arrow function的形式在创建,它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到要state状态的操作。

无状态的组件优点有:

  • 组件不会被实例化,整体渲染性能得到提升

因为组件被精简成一个render方法的函数来实现的,由于是无状态组件,所以无状态组件就不会在有组件实例化的过程,无实例化过程也就不需要分配多余的内存,从而性能得到一定的提升。

  • 组件不能访问this对象

无状态组件由于没有实例化过程,所以无法访问组件this中的对象,例如:this.ref、this.state等均不能访问。若想访问就不能使用这种形式来创建组件

  • 组件无法访问生命周期的方法

因为无状态组件是不需要组件生命周期管理和状态管理,所以底层实现这种形式的组件时是不会实现组件的生命周期方法。所以无状态组件是不能参与组件的各个生命周期管理的。

  • 无状态组件只能访问输入的props,同样的props会得到同样的渲染结果,不会有副作用。
var InputControlES5 = React.createClass({
    propTypes: {//定义传入props中的属性各种类型
        initialValue: React.PropTypes.string
    },
    defaultProps: { //组件默认的props对象
        initialValue: ''
    },
    // 设置 initial state
    getInitialState: function() {//组件相关的状态对象
        return {
            text: this.props.initialValue || 'placeholder'
        };
    },
    handleChange: function(event) {
        this.setState({ //this represents react component instance
            text: event.target.value
        });
    },
    render: function() {
        return (
            <div>
                Type something:
                <input onChange={this.handleChange} value={this.state.text} />
            </div>
        );
    }
});
InputControlES6.propTypes = {
    initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
    initialValue: ''
};

React.createClass是react刚开始推荐的创建组件的方式,这是ES5的原生的JavaScript来实现的React组件,它可以创造有状态的组件,但随着react的发展,使用React.createClass也暴露出一些问题:

React.createClass会自绑定函数方法(不像React.Component只绑定需要关心的函数)导致不必要的性能开销,增加代码过时的可能性。
React.createClass的mixins不够自然、直观;React.Component形式非常适合高阶组件(Higher Order Components--HOC),它以更直观的形式展示了比mixins更强大的功能,并且HOC是纯净的JavaScript,不用担心他们会被废弃。HOC可以参考无状态组件(Stateless Component) 与高阶组件

class InputControlES6 extends React.Component {
    constructor(props) {
        super(props);

        // 设置 initial state
        this.state = {
            text: props.initialValue || 'placeholder'
        };

        // ES6 类中函数必须手动绑定
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(event) {
        this.setState({
            text: event.target.value
        });
    }

    render() {
        return (
            <div>
                Type something:
                <input onChange={this.handleChange}
               value={this.state.text} />
            </div>
        );
    }
}
InputControlES6.propTypes = {
    initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
    initialValue: ''
};

React.Component是以ES6的形式来创建react的组件的,是React目前极为推荐的创建有状态组件的方式,最终会取代React.createClass形式;相对于 React.createClass可以更好实现代码复用
React.createClass与React.Component区别:

React.createClass创建的组件,其每一个成员函数的this都有React自动绑定,任何时候使用,直接使用this.method即可,函数中的this会被正确设置。React.Component创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。
const Contacts = React.createClass({  
  handleClick() {
    console.log(this); // React Component instance
  },
  render() {
    return (
      <div onClick={this.handleClick}></div>
    );
  }
});

class Contacts extends React.Component {  
  constructor(props) {
    super(props);
  }
  handleClick() {
    console.log(this); // null
  }
  render() {
    return (
      <div onClick={this.handleClick}></div>
    );
  }

//或者是:
this.handleClick = this.handleClick.bind(this); //构造函数中绑定
 
<div onClick={this.handleClick.bind(this)}></div> //使用bind来绑定
 
<div onClick={()=>this.handleClick()}></div> //使用arrow function来绑定
组件属性类型propTypes及其默认props属性defaultProps配置不同。

React.createClass在创建组件时,有关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是使用getDefaultProps的方法来获取默认组件属性的。React.Component在创建组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。

const TodoItem = React.createClass({
    propTypes: { // as an object
        name: React.PropTypes.string
    },
    getDefaultProps(){   // return a object
        return {
            name: ''    
        }
    }
    render(){
        return <div></div>
    }
})
 
class TodoItem extends React.Component {
    static propTypes = {//类的静态属性
        name: React.PropTypes.string
    };

    static defaultProps = {//类的静态属性
        name: ''
    };

    ...
}
组件初始状态state的配置不同。

React.createClass创建的组件,其状态state是通过getInitialState方法来配置组件相关的状态。
React.Component创建的组件,其状态state是在constructor中像初始化组件属性一样声明的。

const TodoItem = React.createClass({
    // return an object
    getInitialState(){ 
        return {
            isEditing: false
        }
    }
    render(){
        return <div></div>
    }
})
 
class TodoItem extends React.Component{
    constructor(props){
        super(props);
        this.state = { // define this.state in constructor
            isEditing: false
        } 
    }
    render(){
        return <div></div>
    }
}

this的理解与使用

React可以使用React.createClass、ES6 classes、纯函数3种方式构建组件。使用React.createClass会自动绑定每个方法的this到当前组件,但使用ES6 classes或纯函数时,就要靠手动绑定this,因此绑定方法如下:

使用React.createClass会自动绑定每个方法的this到当前组件
// 使用React.createClass会自动绑定每个方法的this到当前组件
const Contacts = React.createClass({ 
  handleClick() {
    console.log(this); // React Component instance
  },
  render() {
    return (
      <div onClick={this.handleClick}></div>
    );
  }
});
使用箭头函数

箭头函数则会捕获其所在上下文的this值,作为自己的this值,使用箭头函数就不用担心函数内的this不是指向组件内部了---推荐

class LoggingButton extends React.Component {
    handleClick() {
      console.log('this is:', this);
    }
   
    render() {
      // 这个语法确保 `this` 被绑定在 handleClick 中
      return (
        <button onClick={(e) => this.handleClick(e)}>
          Click me
        </button>
      );
    }
  }
使用bind()绑定(不推荐使用,参照下方展开代码)

Function.prototype.bind(thisArg [, arg1 [, arg2, …]]) 是ES5新增的函数扩展方法,bind()返回一个新的函数对象,该函数的this被绑定到thisArg上,并向事件处理器中传入参数

class LoggingButton extends React.Component {
    handleClick(param) {
      console.log('this is:', this);
    }
   
    render() {
      return (
        <button onClick={ this.handleClick.bind(this, 'params') }
          Click me
        </button>
      );
    }
  }
  
// 考虑下面的代码:
class MyCom extends React.Component{
    submit(){
    // do something
    }
  
    render(){
        return <div>
            <Form onSubmit={this.submit.bind(this)} values={{name: '', id: ''}}></Form>
            <Input onChange={v => {this.setState({value: v})}} />
        </div>
    }
}

input 组件每次onChange 都会触发父组件render, 而每次render的时候都会造成子组件Form重新渲染, 当子组件渲染比较复杂时,带来的卡顿将会非常明显!因为bind每次都会产生一个新函数。
构造函数内绑定

在构造函数 constructor 内绑定this,好处是仅需要绑定一次,避免每次渲染时都要重新绑定,函数在别处复用时也无需再次绑定

import React, {Component} from 'react'
 
class Test extends React.Component {
    constructor (props) {
        super(props)
        this.state = {message: 'Allo!'}
        this.handleClick = this.handleClick.bind(this)
    }
 
    handleClick (e) {
        console.log(this.state.message)
    }
 
    render () {
        return (
            <div>
                <button onClick={ this.handleClick }>Say Hello</button>
            </div>
        )
    }
}

react-router的实现原理

首先需要了解 history.pushState 与 popstate 事件,不清楚的点击这里: https://developer.mozilla.org...

react-router 的实现原理参见 :http://zhenhua-lee.github.io/...

从点击 Link 到 render 对应 component ,路由中发生了什么

react的diff算法

react怎么优化

react高阶组件

从时间旅行的乌托邦,看状态管理的设计误区

文章:https://juejin.im/post/5a3707...

聊一聊我对 React Context 的理解以及应用

文章:https://juejin.im/post/5a90e0...

相关参靠资源:

http://blog.csdn.net/heyuan98...
http://www.cnblogs.com/wonyun...


bulinin
138 声望4 粉丝

分享,学习,进步~~~