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> ); }
最近讀了 Kent Dodds 的 How to use React Context effectively ,好奇您在使用 React context 時,是不是也有一套自己的組織方法?