最近在整理CSS自定義屬性在React中的使用時了解到“可以使用React Context API相關的知識更好的在React組件中使用CSS自定義屬性”,但是自己對這方面的知識了解的并不多,因此想借此機會來學習React Context API相關的知識。愛掏網 - it200.com也基于這個原因有了這篇文章。愛掏網 - it200.com
我們從一個React的實例開始。愛掏網 - it200.com假設你要構建一個React的應用,該應用有一個最簡單的功能,就是Dark Mode的切換。愛掏網 - it200.com簡單地說,在Web應用上一個切換組件(比如ThemeToggle
),用戶點擊該切換按鈕可以讓頁面在暗色系(dark
)和亮色系(light
)之間切換。愛掏網 - it200.com
通常我們會通過props
為所有組件提供當前主題的模式,并使用state
來更新當前的主題。愛掏網 - it200.com
在/src/components/
目錄下分別創建了GrandChild
、Child
、ParentComponent
和ThemeToggle
幾個組件:
示例代碼如下:
// /src/components/GrandChild
import React from 'react'
const GrandChild = (props) => {
const styled = {
color: `${props.theme.color}`,
background: `${props.theme.background}`
}
return Theme Toggle
}
export default GrandChild;
// /src/components/Child
import React from 'react'
import GrandChild from '../GrandChild'
const Child = (props) => {
const styled = {
border: `5px solid ${props.theme.color}`,
padding: `10vmin 20vmin`,
borderRadius: '8px'
}
return
}
export default Child
// /src/components/ParentComponent
import React from 'react'
import Child from '../Child'
const ParentComponent = (props) =>
export default ParentComponent
// /src/components/ThemeToggle
import React from 'react'
const ThemeToggle = (props) => {
const styled = {
background: `${props.theme.background}`,
color: `${props.theme.color}`,
border: `4px solid currentColor`,
borderRadius: `6px`,
padding: `2vmin 4vmin`,
margin: `4vmin`,
cursor: `pointer`
}
return
}
export default ThemeToggle
// /src/App.js
import React, {Fragment} from 'react';
import ParentComponent from './components/ParentComponent'
import ThemeToggle from './components/ThemeToggle'
const dark = {
background: '#121212',
color: '#fff'
}
const light = {
background: '#fff',
color: '#444'
}
const App = () => {
const [theme, setTheme] = React.useState('light')
const onClickHander = () => {
theme === 'light' ? setTheme('dark') : setTheme('light')
}
return
}
export default App;
效果如下:
在這個示例中,在ParentComponent
組件中指定了theme
這個props
,并且將這個props
一級一級往下傳,傳給組件樹下的所有組件。愛掏網 - it200.com即,將theme
傳遞到需要它的地方,在本例中會傳到GrandChild
組件。愛掏網 - it200.com而Child
組件和theme
(props
)沒有任何關系,它只是作為一個媒體而以。愛掏網 - it200.com
試想一下,在React中組件樹就有點類似于我們熟悉的DOM樹:
正如上圖所示,我們可以在最底層組件中添加state
,但如果要將數據傳遞給兄弟組件的話,在React Context API之前,我們只能將state
放到他們的父組件中(組件樹中更高的組件位置),然后通過props
將其傳遞回同級組件:
就像上面的示例,我們需要將state
從組件樹的最頂層一級一級往下傳,哪怕是所有中間層組件不需要使用這些數據,但它必須為了后面的組件做為媒介,將state
傳遞到最底層組件。愛掏網 - it200.com
對應到上面的示例中,那就是:
React Context API正是用來解決Prop Drilling的問題。愛掏網 - it200.comReact Context API提供了一種通過Provider
和Consumer
用來提供數據和消費數據,它們可以在組件件中傳遞數據,最主要的是不必要一級一級的通過props
向組件樹傳遞state
。愛掏網 - it200.com簡單地說,在組件樹最頂層的組件中通過Provider
提供數據,在后面的任何一個子組件樹可以通過Consumer
來消費Provider
提供的數據:
React的官網是這樣描述Context的:
在這個特性還沒出現之前,在React應用中數據的通訊是通過props
屬性自上而下(由父及子)進行傳遞的,換句話說,必須通過props
傳遞到每個組件中,然后在組件中重復相同的過程。愛掏網 - it200.com但這種做法對于某些類型的屬性而言是極其繁鎖的,也會變得非常的糟糕,最終可能會導致props
在我們的組件中要不斷的一層一層嵌套。愛掏網 - it200.com
React Context API的出現主要是為了幫助我們解決這方面的問題,它提供了一種在組件之間共享此類值的方式,而不必顯式地通過組件樹的逐層傳遞props
。愛掏網 - it200.com也就是說,它允許父組件隱式地將數據傳遞給子組件(不管組件樹有多深)。愛掏網 - it200.com換句話說,可以將數據添加到父組件中,然后任何子組件都可以訪問它。愛掏網 - it200.com
假設我們有這樣的一個使用場景,在一個React應用中,我們有App
、Container
、Form
和Button
四個組件,它們之間是依次被嵌套:
App ? Container ? Form ? Buttton
假如我們使用props
傳遞就需要一層一層往里傳:
換成Context
,就可以直接獲取最頂層App
組件綁定的值:
對于像我這樣的初級使用者而言,要想徹底的了解React Context API,只能從最簡單的應用開始。愛掏網 - it200.com為了更好的理解它的使用,我們從最簡單的示例開始。愛掏網 - it200.com
創建上下文對象
在React中使用Context的話,我們首要做的就是創建上下文對象(Context Object)。愛掏網 - it200.com可以使用React
上的.createContext()
創建一個Context
對象:
const DataContext = React.createContext()
嘗試著把這個Context
對象DataContext
在控制臺上打印出來:
這個時候可以從組件樹中離自身最近的那個匹配的Prrovider
中讀取到當前的context
值。愛掏網 - it200.com
只有當組件所處的樹中沒有匹配到Provider
時,其defaultValue
參數才會生效。愛掏網 - it200.com這有助于在不使用Provider
包裝組件的情況下對組件進地測試。愛掏網 - it200.com
另外,createContext()
方法提供了Provider
和Consumer
能力,其中一個是提供者,另一個是消費者,而且這兩個屬性都是成對出現的,即每一個Provider
都會有對應的一個Consumer
。愛掏網 - it200.com
Provider
將作為父組件使用,它持有所有Consumer
都可以共享的值。愛掏網 - it200.com注意,Consumer
只能用于Provider
的子組件。愛掏網 - it200.com
使用Provider
提供數據
上一步,使用React.createContext()
創建了一個名為DataContext
的上下文對象,在其中,我們用一些值(value
)初始化一個狀態(state
),可以使用DataContext
的Provider
接受一個value
屬性,傳遞給子組件消費(Consumer
)
const App = () => Child Component
;
Provider
的value
屬性的值可以是字符串、數字或對象。愛掏網 - it200.com
消費Provider
提供的數據
Provider
創建了數據,其創建的數據可以通過context
對象的Consumer
屬性給子組件消費。愛掏網 - it200.com主要有三種方法來消費Provider
屬性創建的數據。愛掏網 - it200.com
使用Consumer
組件消費數據
創建一個新組件,并且在該組件中使用DataContext
的Consumer
來消費數據。愛掏網 - it200.com這將返回一個函數,該函數允許組件消費Provider
中設置的值。愛掏網 - it200.com比如:
const ParagraphChildComponent = () =>
{ value => I'm {value.userName}, {value.age}
包月會員查看