選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
3 分鐘閱讀時間 (543 個字)

React Context

mockuuups-bright-mockup-scene-with-macbook-pro

Context

Context 是用來處理 App 中指定元件樹的公用資訊。

一般來說,資料是由父元件透過子元件定義的Property傳給子元件。

<ChildComponent data={data}/> 

針對某些很多元件都會使用到的資料,使用這種每次用都要傳的傳遞方式很麻煩。

或是定義資料的元件跟實際用到資料的元件差了很多層,

那麼夾在兩者中間的元件就會多了很多次不必要的傳遞。

const App: React.FC = props => {
	const [fontColor, setFontColor] = useState('#000000');
	return <GreatGrandParent fontColor={fontColor}/>
}
const GreatGrandParent: React.FC = props => <GrandParent fontColor={props.fontColor}/>
const GrandParent: React.FC = props => <Parent fontColor={props.fontColor}/>

const Parent: React.FC = props => <>
	<div style={{ color: props.fontColor }}>Hello</div>
	<Child fontColor={props.fontColor}/>
</>

const Child: React.FC = props => <GrandChild fontColor={props.fontColor}/>

const GrandChild: React.FC = props => <div style={{color: props.fontColor}}>World</div> 

這時就是使用 Context 的時候了!

建立一個 Context

使用 React.createContext 建立一個 Context

const defaultValue= {
	fontColor: '#000000'
};

// 當元件樹外層找不到該 Context 的 Provider 時,
// Context 的值會是 defaultValue 。
const ThemeContext = React.createContext(defaultValue); 

使用 Context

1. 在要使用 Context 的元件樹包一層 Provider 

const App: React.FC = props => (
	<ThemeContext.Provider value={{
		fontColor: '#FF0000'
	}}>
		<GreatGrandParent/>
	</ThemeContext.Provider>
) 

[注意] 

  • 就算 Provider 的 value 傳入的是 undefined 也無法使Context 的值為 defaultValue。 只有在元件樹外層找不到該 Context 的 Provider 時,Context 的值才會是 defaultValue。
  • 如果使用了多層Provider , Context 的值會是距離使用元件最近的 Provider 提供的。
const App: React.FC = props => (
	<ThemeContext.Provider value={{
		fontColor: '#FF0000'
	}}>
		<ThemeContext.Provider value={{
			fontColor: '#00FF00'
		}}>
			{ /* GreatGrandParent 得到的 fontColor 是 #00FF00 */ }
			<GreatGrandParent/>
		</ThemeContext.Provider>
	</ThemeContext.Provider>
) 
  • 當 Provider 的 value 改變時,底下的元件會重新 render。 (使用 Object.is 判斷 value 是否改變) 

2. 取得 Context 的值 

 Class Component

  • 使用 contextType (只能使用一個 Context) 
class GreatGrandParent extends React.Component {
  componentDidMount() {
    let value = this.context;
		// ...
  }
  componentDidUpdate() {
    let value = this.context;
		// ...
  }
  componentWillUnmount() {
    let value = this.context;
		// ...
  }
  render() {
    let value = this.context;
		// ...
  }
}
GreatGrandParent.contextType = ThemeContext; 
  • 使用 Context 的 Consumer (可以使用多個 Context)
class App extends React.Component {
  render() {
		return (
			<ThemeContext.Provider value={{
				fontColor: '#FF0000'
			}}>
				<UserContext.Provider value={{
					name: 'world'
				}}>
					<ConsumerWrapper/>
				</UserContext.Provider>
			</ThemeContext.Provider>
		);
  }
}

class ConsumerWrapper extends React.Component {
  render() {
		return (
			<ThemeContext.Consumer>
			{ theme => (
				<UserContext.Consumer>
				{ user => (
					<GreatGrandParent
						color={theme.fontColor}
						user={user.name}/>
				)}
				</UserContext.Consumer>
			)}
			</ThemeContext.Consumer>
		);
	}
}

class GreatGrandParent extends React.Component {
  render() {
		return <div style={{ color: this.props.color }}>
			Hello, { this.props.user }
		</div>
  }
} 

 Function Component

使用 React 內建 Hook: useContext

const App: React.FC = props => {
	return (
		<ThemeContext.Provider value={{
			fontColor: '#FF0000'
		}}>
			<UserContext.Provider value={{
				name: 'world'
			}}>
				<GreatGrandParent/>
			</UserContext.Provider>
		</ThemeContext.Provider>
	);
}

const GreatGrandParent: React.FC = props => {
	const { fontColor } = useContext(ThemeContext);
	const { name } = useContext(UserContext);

	return (<div style={{ color: fontColor }}>
			Hello, { name }
		</div>
	);
} 
每日小知識#6 - 套件管理
每日小知識#5 - dockerfile

相關文章

 

評論 3

Isaac Huang 於 2021/03/25, 週四 15:31

最近讀了 Kent Dodds 的 How to use React Context effectively ,好奇您在使用 React context 時,是不是也有一套自己的組織方法?

最近讀了 Kent Dodds 的 [url=https://kentcdodds.com/blog/how-to-use-react-context-effectively]How to use React Context effectively[/url] ,好奇您在使用 React context 時,是不是也有一套自己的組織方法?
Rita Kuo (郭庭恩) 於 2021/04/02, 週五 17:53

我在使用的時候,也會客製 Provider Component!
不過我覺得使用 useContext 蠻方便的,就沒有特別去客製 Consumer ~
也可以在最外層用一個 Component 去動態包整個專案都會用到的 Provider 們 (比如說主題、工具之類的)。
不知道這樣有沒有回答到你的問題 XD

我在使用的時候,也會客製 Provider Component! 不過我覺得使用 useContext 蠻方便的,就沒有特別去客製 Consumer ~ 也可以在最外層用一個 Component 去動態包整個專案都會用到的 Provider 們 (比如說主題、工具之類的)。 不知道這樣有沒有回答到你的問題 XD
Isaac Huang 於 2021/04/05, 週一 01:30

有!我也還在練習使用 React context ,謝謝你的回答~

有!我也還在練習使用 React context ,謝謝你的回答~
已經注冊了? 這裡登入
Guest
2024/05/10, 週五

Captcha 圖像