學一門新技術,我習慣的學習方式是:html
階段 | 學習目標 | 文檔資源 | 參考資源 |
---|---|---|---|
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嚴格定義了組件的生命週期會經歷以下三個過程:ios
裝載過程(Mount),組件第一次在DOM樹渲染的過程。
更新過程(Update),當組件被從新渲染的過程。
卸載過程(Unmount),組件重DOM樹中刪除的過程。
裝載過程,依次會調用如下函數:git
constructor():ES6類的構造函數(爲了初始化state或綁定this)
getInitialState():ES5中初始化state。
getDefaultProps():ES5中初始化props。在ES6中使用defaultProps()方法。
componentWillMount():在組件被掛載前調用。只執行一次。
render():渲染組件,必須實現該方法。
componentDidMount():在組件裝載後調用。這時已經生成了真實的DOM節點。只執行一次。
更新過程, 當組件的props或者state改變時就會觸發組件的更新過程,依次會調用以下函數:es6
componentWillReceiveProps(nextProps):當父組件的render()方法執行後就會觸發該方法。初始化時不調用。
shouldComponentUpdate(nextProps,nextState):當props改變或state改變時調用,初始化時不掉用,返回boolean。true表示繼續執行render方法,fasle表示放棄本次渲染。
render():渲染組件。
卸載過程:github
componentWillUnmount():將組件從DOM樹移出,防止內存溢出
1.受控組件:受控組件
一個受控的<input>組件都有一個value屬性。渲染一個受控的<input>會展現出value屬性的值。
一個受控的組件不會維護它本身內部的狀態,組件的渲染單純的依賴於props。算法
非受控組件的輸入框相似於傳統的表單輸入,可使用一個ref來獲取它的值。例如,一個按鈕的onClick操做:npm
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。redux
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中設置axios
開始設置值爲空字符串—''
你輸入一個a,而後執行handleNameChange得到a而且設置了setState,而後input輸入框a被從新渲染
你繼續鍵入b,handleNameChange得到ab而且設置state,input輸入框再次被從新渲染,如今的值是value=ab
這種「推入式」的流程改變了表單控件,所以表單控件老是可以一直獲取輸入框當前的值,而不用明確知道對象是誰。這意味着你的數據state以及UIinput老是異步的。狀態將值賦給輸入框,輸入框通知表單改變當前的值
原文請查看:https://goshakkk.name/control...
目前建立組件的方式大概有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.ref、this.state等均不能訪問。若想訪問就不能使用這種形式來建立組件
由於無狀態組件是不須要組件生命週期管理和狀態管理,因此底層實現這種形式的組件時是不會實現組件的生命週期方法。因此無狀態組件是不能參與組件的各個生命週期管理的。
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> } }
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> ) } }
首先須要瞭解 history.pushState 與 popstate 事件,不清楚的點擊這裏: https://developer.mozilla.org...
react-router 的實現原理參見 :http://zhenhua-lee.github.io/...
文章:https://juejin.im/post/5a3707...
文章:https://juejin.im/post/5a90e0...
http://blog.csdn.net/heyuan98...
http://www.cnblogs.com/wonyun...