Context API
react組件中經(jīng)常會遇到這樣一種情況羡微,由于組件嵌套層數(shù)過多導(dǎo)致state管理復(fù)雜傻唾,props傳遞不方便投慈,這個時候你可以使用redux之流來進(jìn)行狀態(tài)管理,但是如果只是個別state難以管理冠骄,redux可能有點(diǎn)殺雞用牛刀了伪煤,這時你可以考慮試一下context API。
在react官網(wǎng)文檔中是這樣來介紹context的:
Context provides a way to pass data through the component tree without having to pass props down manually at every level.(Context提供了一種通過組件樹傳遞數(shù)據(jù)的方法凛辣,而無需在每一級手動傳遞props抱既。)
下面我們一步一步來看一下如何去使用context
- 我們通過React.createContext()創(chuàng)建一個context對象:
const { Provider, Consumer } = React.createContext()
- 然后創(chuàng)建一個返回Provider組件的包裝器組件,并添加要從中訪問上下文的所有組件作為子組件:
class Container extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
}
render() {
return (
<Provider value={{
state: this.state
}}>
{this.props.children}
</Provider>
)
}
}
class Calculator extends React.Component {
render() {
return (
<Container>
<Button />
</Container>
)
}
}
Container組件將是一個全局的Provider扁誓,您還可以創(chuàng)建較小的context防泵。
- 在Provider中包含的組件內(nèi)部,使用Consumer組件來使用context:
class Button extends React.Component {
render() {
return (
<Consumer>
{context => <button>{context.state.count}</button>
</Consumer>
)
}
}
4.您還可以將函數(shù)作為傳遞值給Provider蝗敢,而Consumer可以使用這些函數(shù)來更新context的state:
class Container extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
}
render() {
return (
<Provider value={{
state: this.state捷泞,
addHandle : ()=>{this.setState({count: this.state.count+1})}
}}>
{this.props.children}
</Provider>
)
}
}
/**...**/
<Consumer>
{(context) => (
<button onClick={context.addHandle}>
{context.state.count}
</button>
)}
</Consumer>
這樣一來,你就可以很好的解決了多層組件套用的問題前普。
關(guān)于context更多的用法肚邢,可以參考react官方文檔
高階組件基礎(chǔ)應(yīng)用(HOC)
高階組件在react中是一個非常有用的概念,它有點(diǎn)類似于javascript中的高級函數(shù),比如說Array.map()骡湖,接受函數(shù)作為一個參數(shù)贱纠,在react中,如果一個組件接受一個組件然后返回一個組件响蕴,那么這個組件就可以被稱為高階組件谆焊。
一般來說,高階組件經(jīng)常用來創(chuàng)建高可復(fù)用性的代碼浦夷,舉個例子辖试,我們可以給一個組件去給一個組件添加一些方法或者屬性,或者是一個redux store劈狐。
下面將給出一個最基礎(chǔ)的例子:
const withColor = (Element) =>{
return (
(props) => <Element {...props} color="red" />
)
}
withColor是一個組件罐孝,它傳遞一個組件作為參數(shù),返回一個組件并給這個組件設(shè)置了color為'red'肥缔。
接下來我們使用withColor這個高級組件:
const Button = () => {
return <button>test</button>
}
const ColoredButton = withColor(Button)
最后我們在渲染出ColoredButton組件:
function App() {
return (
<div className="App">
<h1>Hello</h1>
<ColoredButton />
</div>
)
}
這只是一個最基礎(chǔ)的高階組件的示例莲兢,但希望在將這些概念應(yīng)用于更復(fù)雜的場景之前,能夠?qū)斫飧唠A組件的要點(diǎn)有所幫助续膳。
Hooks
Hooks是在React 16.7中引入的新特性改艇,它的作用是能夠讓我們在函數(shù)定義的組件中使用state和生命周期事件,使得函數(shù)組件有一個處理事件的好方法坟岔。
1. 獲取state
我們使用useState()API谒兄,創(chuàng)建一個新的state變量,并且可以修改它社付。 useState()接受state項(xiàng)的初始值承疲,并返回一個包含state變量的數(shù)組,以及您調(diào)用以更改狀態(tài)的方法瘦穆。 由于它返回一個數(shù)組纪隙,我們使用數(shù)組解構(gòu)來訪問每個單獨(dú)的項(xiàng)赊豌,如下所示:
import React, { useState } from 'react'
const Counter = () => {
const [count, setCount] = useState(0)
return (
<div>
<p>總數(shù):{count}</p>
<button onClick={() => setCount(count + 1)}>點(diǎn)擊+1</button>
</div>
)
}
ReactDOM.render(<Counter />, document.getElementById('app'))
你可以盡可能的調(diào)用useState()扛或,來創(chuàng)建你所需要的state變量,而你只需保證在組件的頂層(不在if或任何其他塊中)調(diào)用它就ok了碘饼。
2.使用生命周期函數(shù)
在類組件中熙兔,您擁有componentDidMount,componentWillUnmount和componentDidUpdate等生命周期函數(shù)艾恼,這些函數(shù)提供了從變量初始化到API調(diào)用等等的用例住涉。
在函數(shù)式組件中,Hooks提供useEffect()API钠绍,它接受函數(shù)作為它的參數(shù)舆声,在首次渲染組件時運(yùn)行,在后面每次重新渲染或組件更新時也會運(yùn)行。React首先會更新DOM媳握,然后調(diào)用傳遞給useEffect()的函數(shù)碱屁,與舊的componentDidMount和componentDidUpdate有點(diǎn)類似,但是又有所不同蛾找,因?yàn)檫@些操作都不會阻止UI渲染娩脾,即使是阻塞了代碼,這使我們的APP感覺上更快了打毛。
import React,{ useEffect, useState }from 'react'
const CounterWithNameAndSideEffect = () => {
const [count, setCount] = useState(0)
const [name, setName] = useState('Flavio')
useEffect(() => {
console.log(`Hi ${name} you clicked ${count} times`)
})
return (
<div>
<p>
Hi {name} you clicked {count} times
</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
<button onClick={() => setName(name === 'Flavio' ? 'Roger' : 'Flavio')}>
Change name
</button>
</div>
)
}
ReactDOM.render(
<CounterWithNameAndSideEffect />,
document.getElementById('app')
)
如果我們使用useEffect()有點(diǎn)類似于componentWillUnmount的功能應(yīng)該怎么操作呢柿赊?我們可以在傳遞給useEffect()的函數(shù)里再返回一個函數(shù):
useEffect(() => {
console.log(`Hi ${name} you clicked ${count} times`)
return () => {
console.log(`Unmounted`)
}
})
在每次重新渲染/更新時,useEffect()函數(shù)都會執(zhí)行幻枉,這時我們可以給useEffect添加第二個參數(shù)來告訴React跳過運(yùn)行碰声,這個參數(shù)是一個包含了需要監(jiān)視的state變量的數(shù)組,如果數(shù)組中的其中一項(xiàng)發(fā)生改變熬甫,react將只會重新執(zhí)行useEffect:
useEffect(
() => {
console.log(`Hi ${name} you clicked ${count} times`)
},
[name, count]
)
有點(diǎn)類似的是奥邮,你也可以傳遞一個空數(shù)組,這樣的話罗珍,React只執(zhí)行一次useEffect(在掛載時):
useEffect(() => {
console.log(`Component mounted`)
}, [])
3. Hooks規(guī)則
以上是Hooks的最基本的用法洽腺,理解這些,基本能應(yīng)付大部分的應(yīng)用場景覆旱,在react官方文檔中蘸朋,定義了Hooks的兩條規(guī)則:
- 在最頂層調(diào)用Hooks
不要在循環(huán),條件或嵌套函數(shù)中調(diào)用Hook扣唱。 相反藕坯,始終在React函數(shù)的頂層使用Hooks。 通過遵循此規(guī)則噪沙,您可以確保每次組件呈現(xiàn)時都以相同的順序調(diào)用Hook炼彪。 這就是允許React在多個useState和useEffect調(diào)用之間正確保留Hook狀態(tài)的原因。 - 只在react 函數(shù)式組件中調(diào)用Hooks
不要在普通js函數(shù)中調(diào)用Hooks正歼,你只能在react函數(shù)式組件中調(diào)用Hooks或者在普通的Hooks中調(diào)用Hooks辐马。
更多詳情可以參考Hooks的官方文檔