好程式設計師web前端分享Context-React跨元件訪問資料的利器
好程式設計師web 前端分享 Context-React 跨元件訪問資料的利器
Context 提供了一種跨元件訪問資料的方法。它無需在元件樹間逐層傳遞屬性,也可以方便的訪問其他元件的資料
在經典的React 應用中,資料是父元件透過 props 向子元件傳遞的。但是在某些特定場合,有些資料需要在各個元件之間共享。 Context 為我們提供一種元件之間共享資料的方式,可以避免資料在元件樹上逐層傳遞
使用Context 的場合
Context 可以在元件樹的元件之間共享“全域性”資料。例如:登陸的使用者資訊,使用者選擇的主題、語言等等。下面的例子中,我們“手動”自上而下傳遞theme屬性,用來設定Button的樣式。
class App extends React.Component {
render() {
return <Toolbar theme="dark"></Toolbar> ;
}
}
function Toolbar(props) {
// The Toolbar component must take an extra "theme" prop
// and pass it to the ThemedButton. This can become painful
// if every single button in the app needs to know the theme
// because it would have to be passed through all components.
return (
<div>
<ThemedButton theme={props.theme}></ThemedButton>
</div>
);
}
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme}></Button> ;
}
}
使用 Context ,我們可以避免透過多箇中間元件傳遞props
// Context lets us pass a value deep into the component tree// without explicitly threading it through every component.// Create a context for the current theme (with "light" as the default).const ThemeContext = React.createContext( 'light' );
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.
return (
<ThemeContext.Provider value="dark">
<Toolbar></Toolbar>
</ThemeContext.Provider>
);
}
}
// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
有時候,有些資料需要被很多元件訪問,而且這些元件在元件樹的不同層上。 Context 可以使我們以“廣播”的形式,在各個元件共享資料的改變
Context相關API
React.createContext
const MyContext = React.createContext(defaultValue); 複製程式碼
建立一個新的 Context 物件。當React渲染一個元件,且該元件註冊了 Context 時,它將讀取父元件中,距離該元件最近的Provider元件的 Context 值
defaultValue 只有 在“Consumer”元件找不到Provider元件時,才會被使用。
Context.Provider
<MyContext.Provider value={ /* some value */ }> 複製程式碼
每個 Context 物件都攜帶一個名叫Provider的React元件。Provider可以使得“Consumer”元件監聽context的變更
透過向Provider的後代Consumer元件傳遞value的prop,一個Provider可以與多個Consumer元件建立聯絡。
所有的後代Consumer元件在Provider的value屬性更新後,都會被重新渲染。這個更新從Provider到其後代Consumer元件之間傳播,但是並不會觸發shouldComponentUpdate方法。所以即使Consumer元件的祖先元件沒有更新,Consumer元件也會更新
Context 使用與Object.is相同的演算法來對比value的新、舊值,以判定其value是否被更新了
注意
當向value傳遞物件時,這種判定value是否改變的方式可能會引起問題。
Class.contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this .context;
/* perform a side-effect at mount using the value of MyContext */
}
componentDidUpdate() {
let value = this .context;
/* ... */
}
componentWillUnmount() {
let value = this .context;
/* ... */
}
render() {
let value = this .context;
/* render something based on the value of MyContext */
}
}
MyClass.contextType = MyContext;
為class的contextTpe屬性賦值一個 Context 物件後,我們可以透過this.context在元件的各個宣告週期函式中獲取到當前的 Context 物件的方法
注意:
透過這種方式,每個元件只能註冊一個context物件。如果需要讀取多個context的value值
如果編碼中使用了ES實驗中的語法,那麼可以使用類的靜態(static)成員來初始化contextTYpe.程式碼如下:
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this .context;
/* render something based on the value */
}
}
Context.Consumer
<MyContext.Consumer>
{value => /* render something based on the context value */}
</MyContext.Consumer>
Consumer 是一個監聽context變化的React元件。它使得我們可以在一個函式元件中,監聽contxt的改變。
Consumer 元件要求其子元素為一個函式。該函式的引數接收當前的context的value值,要求返回一個React節點(node) 傳遞給該函式的引數value等於距離此 Consumner 最近的外層Provider元件的context值。如果沒有外層的Provider元件,則等於呼叫createContext()時傳遞的引數值(context的預設值)。
注意
更多關於“子元素為一個函式”的資訊
栗子
在巢狀元件中更新Context
開發中,我們經常需要在某些巢狀結構很深的元件上更新context的value值。此時,我們可以向下傳遞一個函式,用它來更新context的value。程式碼如下:
theme-context.js
// Make sure the shape of the default value passed to// createContext matches the shape that the consumers expect!export const ThemeContext = React.createContext({
theme : themes.dark,
toggleTheme : () => {},
});
theme-toggler-button.js
import {ThemeContext} from './theme-context' ;
function ThemeTogglerButton() {
// The Theme Toggler Button receives not only the theme
// but also a toggleTheme function from the context
return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => (
<button
>
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;
app.js
import {ThemeContext, themes} from './theme-context' ; import ThemeTogglerButton from './theme-toggler-button' ;
class App extends React.Component {
constructor (props) {
super (props);
this .toggleTheme = () => {
this .setState( state => ({
theme :
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
// State also contains the updater function so it will
// be passed down into the context provider
this .state = {
theme : themes.light,
toggleTheme : this .toggleTheme,
};
}
render() {
// The entire state is passed to the provider
return (
<ThemeContext.Provider value={this.state}>
<Content />
</ThemeContext.Provider>
);
}
}
function Content() {
return (
<div>
<ThemeTogglerButton />
</div>
);
}
ReactDOM.render(<App />, document.root);
使用多個Contexts
為了保持React的快速渲染,我們需要將每個consumer元件編寫成一個獨立的元件節點(node)
// Theme context, default to light themeconst ThemeContext = React.createContext( 'light' );
// Signed-in user contextconst UserContext = React.createContext({
name : 'Guest' ,
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this .props;
// App component that provides initial context values
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
// A component may consume multiple contexts
function Content() {
return (
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}
如果有兩個以上的context經常一起使用,我們需要考慮建立一個render prop component一併提供兩個Context
注意
因為context使用引用標示符(reference identity)來判斷何時需要重新渲染,所以有些情況下,當provider的父元素重新渲染時,會觸發consumer的非內部渲染。例如下面程式碼,在每次Provider重新渲染時,會重新渲染所有的consumer元件。因為會一直建立一個新的物件賦值給value(value一直在變)
class App extends React.Component {
render() {
return (
<Provider value={{something: 'something'}}>
<Toolbar />
</Provider>
);
}
}
為了避免這個問題,可以將value放在元件的state中
class App extends React.Component {
constructor (props) {
super (props);
this .state = {
value : { something : 'something' },
};
}
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2663962/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 好程式設計師Web前端分享前端CSS篇程式設計師Web前端CSS
- 好程式設計師web前端分享應該怎樣學好web前端?程式設計師Web前端
- 好程式設計師web前端分享web前端入門知識程式設計師Web前端
- 好程式設計師分享Web前端開發工具程式設計師Web前端
- 好程式設計師web前端教程分享CSS技巧!程式設計師Web前端CSS
- 好程式設計師web前端分享Cookie知識程式設計師Web前端Cookie
- 1. Context - React跨元件訪問資料的利器ContextReact元件
- 1. Context – React跨元件訪問資料的利器ContextReact元件
- 好程式設計師web前端培訓分享小白學web常見的問題程式設計師Web前端
- 好程式設計師web前端分享前端 javascript 練習題程式設計師Web前端JavaScript
- 好程式設計師web前端教程分享web前端基礎知識程式設計師Web前端
- 好程式設計師web前端教程分享三大前端框架相關問題程式設計師Web前端框架
- 好程式設計師web前端教程分享js閉包程式設計師Web前端JS
- 好程式設計師分享Web前端知識之HTML程式設計師Web前端HTML
- 好程式設計師web前端教程分享js模板模式程式設計師Web前端JS模式
- 好程式設計師分享Web前端效能最佳化程式設計師Web前端
- 好程式設計師web前端分享邏輯運算程式設計師Web前端
- 好程式設計師web前端分享高度自適應程式設計師Web前端
- 好程式設計師web前端分享CSS元素型別程式設計師Web前端CSS型別
- 好程式設計師web前端分享HTML基礎篇程式設計師Web前端HTML
- 好程式設計師web前端分享CSS基礎篇程式設計師Web前端CSS
- 好程式設計師web前端分享HTML 字符集程式設計師Web前端HTML
- 好程式設計師web前端分享:如何理解web語義化?程式設計師Web前端
- 好程式設計師web前端分享前端javascript練習題三程式設計師Web前端JavaScript
- 好程式設計師web前端分享前端javascript練習題一程式設計師Web前端JavaScript
- 好程式設計師Web前端分享程式的三大結構(一)程式設計師Web前端
- 好程式設計師web前端分享CSS不同元素margin的計算程式設計師Web前端CSS
- 好程式設計師web前端分享JavaScript中常見的反模式程式設計師Web前端JavaScript模式
- 好程式設計師web前端培訓分享CSS定位的教程程式設計師Web前端CSS
- 好程式設計師web前端分享透過Vue插槽的元件傳遞HTML內容程式設計師Web前端Vue元件HTML
- 好程式設計師web前端分享css初始化程式碼程式設計師Web前端CSS
- 好程式設計師web前端培訓分享學習JavaScript程式設計師Web前端JavaScript
- 好程式設計師Web前端教程分享Vue學習心得程式設計師Web前端Vue
- 好程式設計師web前端分享主流CSS image比較程式設計師Web前端CSS
- 好程式設計師web前端教程分享javascript 練習題程式設計師Web前端JavaScript
- 好程式設計師web前端教程分享JavaScript面試題程式設計師Web前端JavaScript面試題
- 好程式設計師web前端教程分享JavaScript簡寫方法程式設計師Web前端JavaScript
- 好程式設計師web前端培訓分享JavaScript框架J程式設計師Web前端JavaScript框架