文章首發於我的個人github部落格
一段時間以前,我們寫了一篇文章有關我們即將升級我們遺留的生命週期方法,包含著我們慢慢的遷移的策略。在React 16.3.0這個版本中,為了慢慢遷移,我們增加了一些新的生命週期。我們也推薦了一些被長期期待的一些特性:一個官方的context api,一個 forwarding ref,一個ergonomic ref。
Official Context API
這麼長時間以來,React一直提供了一個實驗性的api context.儘管它是一個很有用的工具,我們還是不推薦使用它因為一些隱藏的問題。而且我們一直計劃去用一個更好的api去替代它。
16.3這個版本引入了一個新的context api,它更加的高效,而且他支援各種靜態型別檢查和很深層次的更新。
這有一個例子來說明,你可以想象你注入了了一個“theme”變數去使用新的api
const ThemeContext = React.createContext("light")
class ThemeProvider extends React.Component{
state = {theme: 'light'}
render(){
return (
<ThemeContext.Provider value={this.state.theme}>
{this.props.children}
</ThemeContext.Provider/>
)
}
}
class ThemeButton extends React.Component{
render(){
return (
<ThemeContext.Consumer>
{theme => <Button theme={theme} />}
</ThemeContext.Consumer>
)
}
}複製程式碼
createRef Api
以前,react提供兩種方式去管理refs,一個是字串api,另一個是通過回撥函式。儘管字串這種方法是兩種中最方便的,但是他有一些不完善的地方,所以我們官方建議是用回撥去替代它。
16.3版本中提供了一個新的選項去管理refs,它和字串方式一樣便利,卻沒有它的缺點。
class MyComponent extends React.Component{
constructor(props){
super(props)
this.inputRef = React.createRef()
}
render(){
return <input type="text" ref={this.inputRef} />
}
componentDidMount(){
this.inputRef.current.focus()
}
}複製程式碼
forwardRef Api
通常,React元件是宣告式的,但是有些時候有不可避免的會使用一些dom節點在元件的例項中。很通常的一些情況比如管理聚焦,選擇或者動畫。React提供了refs作為一種方式去解決這個問題。然而,元件封裝提出了一些挑戰。
例如,如果你用元件替代了,繫結在原先元件的ref屬性值就開始指向了外層的包裹元件而不是DOM節點(在函式式的元件中將會是null),這就是被稱讚的“application-level”元件就像評論元件一樣需要被包裝,它能夠干擾葉子節點,例如FancyButon元件,他們的使用方式就和dom節點一樣,或許他們還會暴露出他們的DOM節點。
Ref forwarding是一個新的特性,讓許多元件能夠接收ref,並且傳給它的子元件。eg:
const FancyButton = React.forwardRef((props,ref) => {
<button ref={ref} className="FancyButton">
{this.prop.children}
</button>
})
const ref = React.createRef()
<FancyButton ref={ref}>click,/FancyButton>複製程式碼
用這種方式,組建可以將erf傳遞給DOM button,並且需要的話連線它,就像直接在使用一個dom元件。
當然,ref forwarding並不僅侷限於向葉子元件渲染dom節點,如果你編寫高階元件的話,我們建議你用它自動的向那些被包裹的元件傳遞ref。
Component Lifecycle Changes
React元件的api已經很久沒有改動了。然而,當我們新增了一些新特性(出錯處理和非同步渲染)之後,我們延伸出了這種模型儘管他並不是我們最初計劃的。
例如,利用現有的api,很容易就可以阻止最初的渲染。這是因為有太多的過程去完成一次渲染。我們研究發現,出錯行為的處理並沒有被考慮進去,這樣就會導致記憶體洩漏。而且現在的元件也讓其他過程複雜化。
這些問題使得元件的生命週期被濫用。(componentWillMount,componentWillReceiveProps,componentWillUpdate)。而且令我們困惑的是這些錯誤經常發生在生命週期中。根據這些原因,我們決定使用一些更好的選擇。
我們知道這些改變會影響很多已有的元件。因此,我們會盡可能慢慢的遷移,而且我們會提供一些別的方法。
我們為了放棄這些不安全的生命週期,我們提供了幾個新的:
- getDerivedStateFromProps:替代componentWillReceiveProps這個生命週期更加安全的方法
- getSnapshotBeforeUpdate: 為了支援在元件更新前更加安全的讀取屬性
最後,附上這次api更新嚐鮮的demo