在之前 Lift state 的文章有提过,当我们有两个元件须共用到同一个 state 会将 state 提升然後再向下传给需要的元件。那如果说不只两个,可能有四、五个以上,那我们可能就会再提升,然後再透过 props 一层一层传递。除了透过 props 传递,其实我们还能用 context 来达到帮助我们将 state 传递下去,今天就让我们来介绍如何使用 React context 吧!
在使用 useContext 前必须先使用 createContext 来建立一个 Context object。它可以接收一个参数作为 defaultValue 。
const Context = createContext(defaultValue)
而这个 Context 物件,会有 Provider 属性,那它其实是 React element 所以我们可用 JSX 的形式呈现,并传入 value props 。
<Context.Provider value={/* some value */}>
{children}
</Context.Provider>
而被 Context.Provider 所包含的元件,都可以取得 value。那究竟该怎麽取呢? 这个时候就是用到 useContext 啦!
使用 useContext 并将我们一开始使用 createContext 所回传的 Context object 传入就能够取得我们在 provider 提供的 value 了!
const value = useContext(Context)
以上就是 useContext 与 createContext 的搭配使用,接下来就让我们来看看范例,加深对 context 的印象吧!
假设我们有个 App 结构如下
// App.jsx
import { Header } from './components/Header'
import { Body } from './components/Body'
import { Footer } from './components/Footer'
function App() {
const [ darkTheme, setDarkTheme ] = React.useState(false)
const theme = darkTheme ? 'dark' : 'light'
return (
<>
<Header themeState={[theme, setDarkTheme]}/>
<Body theme={theme}/>
<Footer themeState={[theme, setDarkTheme]}/>
</>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
// Header.jsx
import { ButtonTheme } from './ButtonTheme'
function Header({themeState}) {
return (
<div>
<ButtonTheme themeState={themeState}/>
</div>
)
}
// Footer.jsx
import { ButtonTheme } from './ButtonTheme'
export function Footer({themeState}) {
return (
<div>
<ButtonTheme themeState={themeState}/>
</div>
)
}=
// Body.jsx
export function Body({theme}) {
return (
<div>
{theme}
</div>
)
}
// ButtonTheme.jsx
export function ButtonTheme({themeState}) {
return (
<div>
<Button themeState={themeState} />
</div>
)
}
function Button({themeState}) {
const [theme, setDarkTheme] = themeState
return (
<button onClick={() => { setDarkTheme(prev => !prev) }}>
{theme}
</button>
)
}
范例中,我们希望按下 Header 或是 footer 的按钮都可以改变 theme 的值,这个时候第一种做法就是在 App 元件建立 useState 并传下去让 button 透过 onClick 去更改状态,那 Body 元件也能够同步更换 theme 。那我们就尝试使用 context 来试试看!
// ThemeContext.js
const ThemeContext = React.createContext('light')
export function ThemeContextProvider({ children }) {
const [darkTheme, setDarkTheme] = React.useState(false)
const theme = darkTheme ? 'dark' : 'light'
return (
<ThemeContext.Provider value={[theme, setDarkTheme]}>
{children}
</ThemeContext.Provider>
)
}
export function useThemeContext() {
const contextValue = React.useContext(ThemeContext)
if (!contextValue) {
throw new Error('you should wrap the component in theme context provider')
}
return contextValue
}
// App.jsx
import { Header } from './components/Header'
import { Body } from './components/Body'
import { Footer } from './components/Footer'
import { ThemeContextProvider } from './components/ThemeContext'
function App() {
return (
<ThemeContextProvider>
<Header />
<Body />
<Footer />
</ThemeContextProvider>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
function Body() {
return (
<div>
{theme}
</div>
)
}
function Header() {
return (
<div>
<ButtonTheme />
</div>
)
}
function Footer() {
return (
<div>
<ButtonTheme />
</div>
)
}
function ButtonTheme() {
return (
<div>
<Button />
</div>
)
}
import { useThemeContext } from './components/ThemeContext'
function Body() {
const [theme] = useThemeContext()
return (
<div>
{theme}
</div>
)
}
import { useThemeContext } from './components/ThemeContext'
function Button() {
const [theme, setDarkTheme] = useThemeContext()
return (
<button onClick={() => { setDarkTheme(prev => !prev) }}>{theme}</button>
)
}
这样我们就成功地使用 context 改写啦!可以发先使用 context 的写法,我们就不需要透过 props 一层一层的传递,只要在使用的元件中使用 useContext 就可以拿到 value。
以上就是关於 useContext 与 createContext 的使用方式!有什麽问题都欢迎在下方留言告诉我~~
该文章同步发布於:我的部落格
<<: 2.4.11 Design System - Switches/Toggle
API流程 I have A Nonce, I have A key, Uh It's time t...
在上一篇,我们把 Ktor client 加到 Dagger 的 object graph 内。现在...
呼 ~ 终於到了最後一天了,这三十天,说真的有点痛苦煎熬 XD 不过我们先来回顾这次铁人赛介绍了哪些...
这个 30 天我们理解了 C 语言与 Objective-C,然而我其实有不少事情是没有看懂的,铁人...
适用人员: 技术人员。 适用法规: 资通安全责任等级分级办法 技术面分类提要 网路架构 端点安全防护...