根據胡子大哈的文章學習,感謝大胡分享
胡子大哈-高階組件、context
高階組件
什么是高階組件
高階組件就是一個函數,傳給他一個組件,他返回一個新的組件。這個新組件會使用傳入的組件作為其子組件。
高階組件體現的是——設計
核心思想:抽象具有相同需求邏輯的組件,用函數處理
例子:
可能有很多組件有這樣需求:“在組件掛載階段,從LocalStorage加載某字段”
定義高階組件src/Component/wrapWithLoadData.js
:
import React, { Component } from 'react'
export default (WrappedComponent, name) => {
class NewComponent extends Component {
constructor () {
super()
this.state = { data: null }
}
componentWillMount () {
let data = localStorage.getItem(name)
this.setState({ data })
}
render () {
return <WrappedComponent data={this.state.data} />
}
}
return NewComponent
}
使用高階組件:
import wrapWithLoadData from './wrapWithLoadData'
class InputWithUserName extends Component {
render () {
return <input value={this.props.data} />
}
}
InputWithUserName = wrapWithLoadData(InputWithUserName, 'username')
export default InputWithUserName
可以看到,InputWithUserName
組件,在內部其從LocalStorage
加載字段的邏輯,直接是用的高階組件包裝。不用自己再寫了。
那么高階組件的作用也就一目了然了:組件之間代碼復用。
組件們可能有某些相似的邏輯,把這些邏輯抽象,做成高階組件,來達到復用效果。在高階組件內部,通過props
把數據傳遞給被包裝的組件。
高階組件的靈活性
高階組件本質是裝飾者模式,通過組合方式,達到很高的靈活性。
比如,上邊的InputWithUserName
不從LocalStorage
加載,而是使用Ajax
請求從服務器加載。那么,不需要修改組件邏輯,而是新寫一個wrapWithAjaxData
的高階組件,然后包裝InputWithUserName
組件就可以了。
多層高階組件
兩個高級組件:wrapWithLoadData``wrapWithAjaxData
其中wrapWithAjaxData
具體內容
...
componentWillMount () {
ajax.get('/data/' + this.props.data, (data) => {
this.setState({ data })
})
...
我們的邏輯是,先從localStorage中拿到username,然后根據username從后臺拿到用戶的具體數據。
修改InputWithUserName
import wrapWithLoadData from './wrapWithLoadData'
import wrapWithAjaxData from './wrapWithAjaxData'
class InputWithUserName extends Component {
render () {
return <input value={this.props.data} />
}
}
InputWithUserName = wrapWithAjaxData(InputWithUserName)
InputWithUserName = wrapWithLoadData(InputWithUserName, 'username')
export default InputWithUserName
React.js的context
全局空間:父組件設置context并放入某狀態,其下每個孩子組件都可以從其取得狀態,而不用一層一層的向下傳遞。(更改了,就會重新渲染一遍)
爺爺組件是訪問不到context的。
寫法
static childContextTypes = {
<key>: PropTypes.<類型>
}
getChildContext () {
return {
<key>: <value>
}
}
childContextTypes
:是為context中的字段設置類型檢查,必須設置
getChildContext()
:用來設置組件的context
若在子組件要使用,可以寫
class Title extends Component {
static contextTypes = {
themeColor: PropTypes.string
}
render () {
return (
<h1 style={{ color: this.context.themeColor }}>React.js 小書標題</h1>
)
}
contextTypes
首先要類型檢查,必須的
this.context.<key>
即可獲取
總結
context
打破了組件之間必須通過props
傳遞狀態的過程,類似一個全局變量空間,其內容能被隨意接觸修改。這樣導致程序不可控。
這種機制,對于狀態管理有很大幫助,redux-react就是充分利用了這個機制。
一般我們動手寫context,而是利用第三方狀態管理庫。