一 学习方式
学一门新技术,我习惯的学习方式是:
- 首先,先1-2遍官方文档。每个方法api都过一遍,有个大概的印象,记录下当时没懂的问题。
- 然后,根据文档中例子,实际动手自己去做一遍
- 接着,去分析项目里的代码,找一个有代表性的页面,分析这个页面的code,结合官方文档api,查漏补缺模糊、不懂的知识点。
- 之后,再笼统的大概分析下其他页面的代码,记录下问题,带着疑问再倒回去把官方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严格定义了组件的生命周期会经历如下三个过程:
装载过程(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...