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 的時候了!
使用 React.createContext 建立一個 Context
const defaultValue= { fontColor: '#000000' }; // 當元件樹外層找不到該 Context 的 Provider 時, // Context 的值會是 defaultValue 。 const ThemeContext = React.createContext(defaultValue);
const App: React.FC = props => ( <ThemeContext.Provider value={{ fontColor: '#FF0000' }}> <GreatGrandParent/> </ThemeContext.Provider> )
[注意]
const App: React.FC = props => ( <ThemeContext.Provider value={{ fontColor: '#FF0000' }}> <ThemeContext.Provider value={{ fontColor: '#00FF00' }}> { /* GreatGrandParent 得到的 fontColor 是 #00FF00 */ } <GreatGrandParent/> </ThemeContext.Provider> </ThemeContext.Provider> )
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;
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> } }
使用 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> ); }
When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.
評論 3
最近讀了 Kent Dodds 的 How to use React Context effectively ,好奇您在使用 React context 時,是不是也有一套自己的組織方法?
我在使用的時候,也會客製 Provider Component!
不過我覺得使用 useContext 蠻方便的,就沒有特別去客製 Consumer ~
也可以在最外層用一個 Component 去動態包整個專案都會用到的 Provider 們 (比如說主題、工具之類的)。
不知道這樣有沒有回答到你的問題 XD
有!我也還在練習使用 React context ,謝謝你的回答~