目錄
- useContext
- 1、Provider和 useContext
- 2、Provider 和Consumer
- 3、Provider 嵌套
- 4、React.createContext提供的Provider和class的contextType屬性
- 5、讀、寫Context
- (1)父組件修改Context
- (2)子組件修改Context
- 好書推薦
useContext官方地址
使用 Context 深度傳遞數據
通常,您會通過 props 將信息從父組件傳遞到子組件。但是,如果您必須通過中間的許多組件傳遞信息,或者應用中的許多組件都需要相同的信息,則傳遞 props 會變得冗長且不方便。Context允許父組件向其下方樹中的任何組件(無論深度如何)提供一些信息,而無需通過 props 明確傳遞。
簡單來說使用Context
可以實現跨組件層級傳遞數據,不用層層傳遞數據。本文介紹三種Context
的使用方式。
- 函數組件:
React.createContext
提供的Provider
和useContext
鉤子 React.createContext
提供的Provider
和Consumer
- Provider嵌套
- Class組件:
React.createContext
提供的Provider
和class
的contextType
屬性 - 讀、寫
Context
useContext
useContext是一個 React Hook,可讓您從組件讀取和訂閱上下文。
用法:
const value = useContext(SomeContext)
參數的含義:
SomeContext:使用createContext創建的上下文。上下文本身并不包含信息,它只代表您可以提供或從組件中讀取的信息類型。
返回值的含義:
value:useContext返回調用組件的上下文值,傳遞給最接近的SomeContext的值。
1、Provider和 useContext
新建個context.js,導出createContext()的返回值
import { createContext } from "react";
export default createContext();
App.js,導入上面寫的context,并使用context提供的Provider組件進行包裹,圈定局部的全局作用域,傳值后可以提供給子組件進行消費。當 Provider 的 value 值發生變化時,它內部的所有消費組件都會重新渲染。
import Context from "./context";
import Test from "./Test"
function App() {const value = "app 中的數據"return (<><Context.Provider value={value}><div className="Appy" ><Test /></div></Context.Provider></>);
}export default App;
新建個Test.js,
import Context from "./context"
import MyComponent from "./MyComponent"
const Test1 = () => {return <><MyComponent/><div></div></>
}
export default Test1
新建個MyComponent.js,使用useContext鉤子接收Context提供的參數
import Context from "./context"
import { useContext } from "react"
const MyComponent = ()=>{const value = useContext(Context)return <><div>value:{value}</div></>
}
export default MyComponent
可以看到頁面中顯示如下:
使用Components分析如下:
2、Provider 和Consumer
上面的MyComponent.js
文件,我們可以使用Context.Consumer組件接收數據。在MyComponent組件中,導入context,使用其提供的Consumer組件來訂閱Context的變更,需要一個函數作為子元素,函數的第一個形參便是Provider組件提供的value值。如下:
import Context from "./context"
import { useContext } from "react"
const MyComponent = ()=>{const value = useContext(Context)return <><Context.Consumer>{value=><div>value1:{value}</div>}</Context.Consumer></>
}
export default MyComponent
3、Provider 嵌套
新建context.js,創建ThemeContext,AuthContext,然后再分別創建創建 ThemeContext 、AuthContext 的 Provider 組件,Provider 組件主要提供方法。
// context.js
import React, { createContext, useState, useContext } from 'react';// 創建 ThemeContext
const ThemeContext = createContext();// 創建 ThemeContext 的 Provider 組件
const ThemeProvider = ({ children }) => {const [theme, setTheme] = useState('light'); // 假設初始主題是 'light'// 可以通過函數來切換主題const toggleTheme = () => {setTheme(theme === 'light' ? 'dark' : 'light');};return (<ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>);
};// 創建 AuthContext
const AuthContext = createContext();// 創建 AuthContext 的 Provider 組件
const AuthProvider = ({ children }) => {const [user, setUser] = useState(null); // 假設初始用戶是 null// 可以通過函數來設置用戶const login = (userData) => {setUser(userData);};const logout = () => {setUser(null);};return (<AuthContext.Provider value={{ user, login, logout }}>{children}</AuthContext.Provider>);
};// 導出 ThemeProvider 和 AuthProvider,以及它們各自的 Context
export { ThemeContext, ThemeProvider, AuthContext, AuthProvider };
App.js,導入ThemeProvider, AuthProvider,層層嵌套。
import React from 'react';
import { ThemeProvider, AuthProvider } from './context.js'; // 導入提供者
import MyComponent from './MyComponent'; // 假設您有一個 MyComponent 組件const App = () => {return (<ThemeProvider ><AuthProvider ><MyComponent /> {/* MyComponent 現在可以訪問 ThemeContext 和 AuthContext */}</AuthProvider></ThemeProvider>);
};export default App;
MyComponent.js,導入ThemeContext, AuthContext ,使用useContext獲取ThemeContext, AuthContext 的Provider組件傳遞的參數。
import React, { useContext } from 'react';
import { ThemeContext, AuthContext } from './context.js'; // 導入 Contextconst MyComponent = () => {console.log(useContext(ThemeContext),'useContext(ThemeContext)')const { theme, toggleTheme } = useContext(ThemeContext);const { user, login, logout } = useContext(AuthContext);console.log(useContext(AuthContext),'useContext(ThemeContext)')// 使用 theme、toggleTheme、user、login 和 logout 做一些事情...return (// ... 組件的 JSX<div><p>當前主題: {theme}</p><button onClick={toggleTheme}>切換主題</button>{user ? (<div><p>已登錄用戶: {user.name}</p><button onClick={logout}>登出</button></div>) : (<button onClick={() => login({ name: 'John Doe' })}>登錄</button>)}</div>);
};export default MyComponent;
頁面如下:
4、React.createContext提供的Provider和class的contextType屬性
static contextType 是一種在類組件中直接訪問 Context 值的方式,而不必明確地傳遞一個 <Context.Consumer> 組件。static contextType 應該被定義在類組件的外部,而不是在 render 方法內部或組件的類體內部。
掛載在 class 上的 contextType 屬性會被重賦值為一個由React.createContext() 創建的 Context 對象。這能讓你使用 this.context 來消費最近 Context 上的那個值。你可以在任何生命周期中訪問到它,包括 render 函數中。
使用static關鍵字添加靜態屬性,和直接在class添加屬性效果一致,最終都會添加到類上,而不是類的實例上
import React, { Component } from "react";
import context from "./context";
class Test1 extends Component {static contextType = context;render() {console.log(Test1.contextType,'contextType');console.log(this.context,'context');const value = this.context;return <div>第三種使用Context方式獲取的值:{JSON.stringify(value)}</div>;}
}// Test1.contextType = context; //此處與寫static關鍵字作用一致
export default Test1;
可以看到打印的Test1.contextType
為React.createContext()
創建的 Context
對象,打印this.context
為最近的 Context 上的值
5、讀、寫Context
(1)父組件修改Context
App.js中,更改Context
數據,調用組件中的onChange
方法。Provider的value不再傳入一個簡單結構的對象,而是將useState的返回值作為新對象的key/value,子組件便能調用App的setStore函數進行更新
import Context from "./context";
import Test from "./Test1"
import { useState } from "react"
function App() {const value = "app 中的數據"const [store, setStore] = useState(value);const onChange = ()=>{setStore("app 數據 change")}return (<><Context.Provider value={{store, setStore}}><div className="Appy" ><Test /><button onClick={onChange}>按鈕</button></div></Context.Provider></>);
}export default App;
Test.js中,使用useContext
接收Context
數據。點擊父組件中的按鈕,數據從 app 中的數據
變為app 數據 change
import Context from "./context"
import { useContext } from "react"
const Test1 = () => {const value = useContext(Context)console.log(value,'test1組件接收到的')return <>{value.store}<div></div></>
}
export default Test1
(2)子組件修改Context
這里更改子組件的代碼,新增一個button按鈕,使用context接收過來的setStore函數,修改Context數據。點擊button之后,數據由app 中的數據
變為子組件修改Context成功
。效果與在父組件中修改Context數據一樣。
import Context from "./context"
import { useContext } from "react"
// import MyComponent from "./MyComponent"
const Test1 = () => {const context = useContext(Context)return <>{value.store}<button onClick={()=>context.setStore("子組件修改Context成功")}>子組件button</button></>
}
export default Test1
好書推薦
《Rust Web開發》
如果你厭倦了緩慢、占用大量資源且不穩定的模板化Web開發工具,Rust就是你的解決方案。Rust服務提供了穩定的安全保證、非凡的開發經驗,以及能夠自動防止常見錯誤的編譯器。
《Rust Web開發》教你使用Rust以及重要的Rust庫(如異步運行時的Tokio、用于Web服務器和API的Warp,以及運行外部HTTP請求的Reqwest)來創建服務端的Web應用。《Rust Web開發》包含大量的代碼示例以及專業的提示,以幫助你創建項目和組織代碼。隨著學習的深入,你將創建一個完整的Q&A Web服務并逐章迭代你的代碼,就像參與了真實的項目開發一樣。
這不是一本參考書,而是一本工作手冊。正在構建的應用程序在設計上做出了一些妥協,以便在適當的時候解釋概念。需要閱讀整本書的內容才能最終將應用程序部署到生產環境中。