此文適合react新手入門,react大佬能夠略過(畢竟之前都是寫vue,React才寫了一個多月, 掩面淚奔)html
主要是學習react中的一些經驗總結,若是你以爲對你有幫助,能夠給個贊github。vue
react項目入門react
react版本:16.0.0 (由於工做中仍是15的版本)git
首先咱們先來講說 有狀態組件和無狀態組件github
有狀態組件:組件內部狀態發生變化,須要state來保存變化。redux
無狀態組件:組件內部狀態是不變的,用不到state。建議寫成函數組件後端
組件設計思路:經過定義少部分有狀態組件管理整個應用的狀態變化,而且將狀態經過props傳遞給其他無狀態組件。 設計模式
有狀態組件主要關注處理狀態變化的業務邏輯,無狀態組件主要關注組件UI渲染工做。這樣更有利於組件的複用,組件之間解耦更加完全數組
這樣有時就會產生一個問題,若是給UI組件加不一樣的邏輯怎麼辦?bash
2種比較好的方法, this.props.children 和 HOC , 具體實例。那麼下面就來詳細說說 HOC 高階組件
知識前置:
裝飾器設計模式:容許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是做爲現有的類的一個包裝。
這種模式建立了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。
在JS中高階函數能夠接受一個函數做爲參數,返回值做爲也是函數的函數。相似的 高階組件也能夠接受一個組件爲參數,返回一個被加工過的組件。
本質上高階函數是一個函數,而不是組件。
例子:
在被包裝的組件接收到props以前。高階組件能夠先攔截到props,對props執行增刪改等操做,而後將修改過的props傳給被包裝組件。
import React, { Component } from 'react'
function withPersistentData (wrapedComponent) {
return class extends Component {
componentWillMount() {
let data = localStore.getItem('data');
this.setState({data})
}
render () {
const { data } = this.state;
// 經過{...this.props} 把傳給當前組件的值繼續傳給被包裝的組件
return <wrapedComponent data={data} {...this.props} />
}
}
}
@withPersistentData
export default class myComponent extends Component {
render() {
return (
<div>
{this.props.data}
</div>
)
}
}
複製代碼
高階組件經過ref獲取被包裝的組件實例的引用,而後高階組件就具有了直接操做被包裝組件的屬性和方法的能力。
function withRef (wrapedComponent) {
return class extends Component {
someMethod = () => {
// this.wrapedComp 被包裝組件實例
// someMethodWrapedComp 被包裝組件的方法
this.wrapedComp.someMethodWrapedComp()
}
render () {
// 經過{...this.props} 把傳給當前組件的值繼續傳給被包裝的組件
// 給被包裝的組件添加ref屬性,獲取被包裝組件實例並賦值給this.wrapedComp
return <wrapedComponent ref={(comp) =>{this.wrapedComp = comp}} {...this.props} />
}
}
}
複製代碼
上面已經說過 無狀態組件更容易被複用,咱們能夠利用高階組件將本來受控組件中須要本身維護的的狀態統一提高到高階組件中,受控組件無狀態化。
import React, { Component } from 'react'
function withControlledComp(wrappedComp) {
state = {
value : null,
}
handleValueChange = (e) => {
this,setState({value: e.target.value})
}
render () {
const newProps ={
controlledProps: {
value: this.state.value,
onChange: this.handleValueChange
}
}
return <wrappedComp {...this.props} {...newProps} />
}
}
@withControlledComp
class ControlledComp extends Component {
render () {
// 此時的受控組件爲無狀態組件,狀態由高階組件控制
return <input {...this.props.controlledProps} />
}
}
複製代碼
function withRedColor (wrapedComponent) {
return class extends Component {
render () {
return (<div style={color: 'red}><wrapedComponent {...this.props} /> </div>) } } } 複製代碼
在第一個操做props的例子裏,若是要獲取key值不肯定時,這個組件就不知足了。
咱們通常採用這種方式:HOC(...params)(wrappedComp)
function withPersistentData = (key) => (wrapedComponent) => {
return class extends Component {
componentWillMount() {
let data = localStore.getItem(key);
this.setState({data})
}
render () {
const { data } = this.state;
// 經過{...this.props} 把傳給當前組件的值繼續傳給被包裝的組件
return <wrapedComponent data={data} {...this.props} />
}
}
}
class myComponent extends Component {
render() {
return (
<div>
{this.props.data}
</div>
)
}
}
// 獲取key=‘data’的數據
const myComponentWithData = withPersistentData('data')(myComponent)
// 獲取key=‘name’的數據
const myComponentWithData = withPersistentData('name')(myComponent)
複製代碼
實際上這種形式的高階組件大量出如今第三方的庫中,例如react-redux中的connect函數
connect(mapStateToProps, mapDispatchToProps)(wrappedComponent)
複製代碼
掛載階段
1. constructor
2. componentWillMount
3. render
4. componentDidMount
複製代碼
使用場景
1. coustructor
一般用於初始化組件的state以及綁定事件的處理方法(好比bind(this))等
2. componentWiillMound
在組件被掛載到DOM前調用,且只會調用一次,
實際項目中比較少用到,由於能夠在該方法中的執行的均可以提到coustructor中
在這個方法中this.setState不會引發從新渲染
3. render
渲染方法。
注意:render只是返回一個UI的描述,真正渲染出頁面DOM的工做由react本身完成
4. componentDidMount
在組件被掛載到DOM後調用,且只會調用一次,
一般用於像後端請求數據
在這個方法中this.setState會引發組件的從新渲染
複製代碼
更新階段
1. componentWillReceiveProps
2. shouldComponentUpdate
3. componentWillUpdate
4. render
5. componentDidUpdate
複製代碼
使用場景
1. componentWillRceiveProps(nextProps)
這個方法只在props引發組件更新時調用。
通常會比較一下this.props和nextProps來決定是否執行props變化後的邏輯
好比:根據新的props調用this.setState來觸發組件的從新渲染
2. shouldComponentUpdate(nextProps,nextState)
這個方法決定組件是否繼續執行更新過程。
默認是true,繼續更新;false阻止更新。
通常是經過比較nextPops,nextState和當前組件的props,state來決定返回結果。
這個方法能夠減小沒必要要的渲染,優化組件性能。
緣由:根據渲染流程,首先會判斷shouldComponentUpdate是否須要更新。若是須要更新,調用render方法生成新的虛擬DOM與舊的虛擬DOM進行對比(render只是返回一個UI描述),若是對比不一致,則根據最小粒度改變去更新DOM。
3. componentWillUpdate
render前調用,組件更新前執行某些邏輯的地方。
通常不多用到。
4. render
5. componentDidUpdate(prevProps, prevState)
組件更新後被調用,能夠做爲操做更新後DOM的地方。
這個方法中的prevProps和prevState表明組件中更新前的props和state。
注意:在render前的生命週期中,componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate中的this.state依然指向更新前的state。
複製代碼
銷燬階段
componentWillUnmount
組件卸載前被調用。
清除定時器,清除componentDidMount中手動建立的DOM,取消請求等
複製代碼
結束語
最後感謝能看到這裏的朋友,由於水平有限,若是有錯誤敬請指正,十分感激。
參考:
react進階之路