React 16.3 finally made the stable. Since then, many developers started using it to solve the “prop-drilling” problem — the issue where you need to pass a down the component tree along components not making use of it in order to access that in a component being rendered the tree. The documentation states the intent of the Context API as follows: Context API prop prop deep down React In a typical React application, is passed top-down (parent to child) via props, but this can be cumbersome for certain types of props (e.g. locale preference, UI theme) that are required by many components within an application. Context provides a way to share values like this between components without having to explicitly pass a prop through every level of the tree. data Context is designed to for a tree of React components, such as the current authenticated user, theme, or preferred language. share data that can be considered “global” Let’s look at the example of tracking the activity of the user. For that, we want to call a certain function every time the user clicks on a UI element. track Tracker in plain React const track = event => console.log(`${event} occured`);class App extends React.Component { render() { return <Toolbar track={track} />; }}function Toolbar(props) { return ( <div> <TrackedButton track={props.track} /> </div> );}function TrackedButton(props) { const onClick = () => { props.track("button click"); // do something on click }; return <Button onClick={onClick} />;} We need the function in many different components of the app, and using React without any advanced patterns we need to pass through the whole component tree, even though and make no use of it. track track App Toolbar Tracker with Context We can use the new React Context API to inject the function into the needed components: track const track = event => console.log(`${event} occured`);const TrackerContext = React.createContext(track);class App extends React.Component { render() { return ( <TrackerContext.Provider value={track}> <Toolbar /> </TrackerContext.Provider> ); }}function Toolbar(props) { return ( <div> {/* does not need to forward props anymore */} <TrackedButton /> </div> );}function TrackedButton(props) { return ( <TrackerContext.Consumer> {value => ( <Button onClick={() => { // call track value("button click"); // do something on click }} /> )} </TrackerContext.Consumer> );} We create a , wrap the root component with which makes the function as in the component. TrackerContext Provider track consumable value TrackedButton However, this is not something we couldn’t do prior to the API, you (Higher Order Component) in React. The code is even more readable using a HOC. Context could always do this with a HOC Tracker as a HOC We can create a HOC, a function taking a component and returning a new component rendering the original component with some enhancements. In our case, we will just inject the function as a into the inner component. track prop const track = event => console.log(`${event} occured`);const withTracker = track => Component => (props) => ( <Component track={track} {...props}/>);class App extends React.Component { render() { return ( /* no need to wrap root Component */ <Toolbar /> ); }}function Toolbar(props) { return ( <div> {/* need to use the HOC here */} <TrackedButtonWrapped /> </div> );}// TrackedButton is the same as in first solutionfunction TrackedButton(props) { const onClick = () => { props.track("button click"); // do something on click }; return <Button onClick={onClick} />;}// Need to create a higher-order component out of TrackedButtonconst TrackedButtonWrapped = withTracker(track)(TrackedButton) The nice thing about this is that the code is a lot cleaner than with using : Context needs no wrapper anymore. App ContextProvider is exactly the same component as in the plain React solution. It's not its responsibility anymore to retrieve the function. This is because we shifted the retrieval into the which we render in instead. TrackedButton track prop **TrackedButtonWrapped** HOC Toolbar So is React.createContext useless? Let’s go back to the example given in the . There, is used to an app. React documentation Context theme Theming with Context The code is similar to the example. provides the and a function to which sets in the root component. These variables are only consumed where needed - in the to style the button and toggle the theme on button click. Tracking with Context ThemeContext.Provider theme toggle the theme state ThemedButton const ThemeContext = React.createContext();class App extends React.Component { state = { theme: 'light' } toggleTheme = () => { this.setState(({ theme }) => ({ theme: theme === 'light' ? 'dark' : 'light', })); } render() { const value = { theme: this.state.theme, toggleTheme: this.toggleTheme, } return ( <ThemeContext.Provider value={value}> <Toolbar /> </ThemeContext.Provider> ); }}function Toolbar(props) { return ( <div> <ThemedButton /> </div> );}function ThemedButton(props) { return ( <ThemeContext.Consumer> {({ theme, toggleTheme }) => <Button theme={theme} onClick={toggleTheme}/>} </ThemeContext.Consumer> );} Theming as a HOC: First try Let’s try to apply the same HOC pattern that we did with to . Tracking Theming Spoiler: It won’t work. const withTheme = InnerComponent => class extends React.Component { state = { theme: 'light' } toggleTheme = () => { this.setState(({ theme }) => ({ theme: theme === 'light' ? 'dark' : 'light', })); } render() { return ( <InnerComponent theme={this.state.theme} toggleTheme={this.toggleTheme} /> ) }}class App extends React.Component { render() { return ( // again no Provider needed <Toolbar /> ); }}function Toolbar(props) { return ( <div> {/* use the HOC here */} <ThemedButtonWrapped /> {/* let's add another Button here */} <ThemedButtonWrapped /> </div> );}function ThemedButton(props) { return <Button onClick={props.toggleTheme} theme={props.theme} />;}// Need to create a higher-order component out of ThemedButtonconst ThemedButtonWrapped = withTheme(ThemedButton) If we add another , you'll notice that it doesn't work here. Every time the HOC is created, the component instance starts with a fresh , and so the buttons' themes are independent of each other. You can play around with it . What’s wrong here? ThemedButton state here _CodeSandbox is an online editor tailored for web applications._codesandbox.io CodeSandbox In the tracking example the data ( function) is and never changed, so each Button instance using the same function is not a problem here. Why did it work in the tracking example? track static This is the big advantage of the over the and why it is so powerful: . Context API HOC pattern Using **Context** the data is among all shared **Consumers** Summary Here’s again what the React documentation says about the use-cases of : Context Context is designed to share data that can be considered “global” for a tree of React components I would go one step further and say that the is for global data that is . In the case of data, you might not need . It can always be replaced with a simpler to use HOC that injects the . Context API dynamic used by multiple component instances static Context props Here’s a general guideline how to decide whether to use React’s API: Context Originally published at cmichel.io