A quick intro to new React Context API and why it won't replace state management libraries

June 12, 2018 0 Comments

A quick intro to new React Context API and why it won't replace state management libraries

 

 

In React 16.3, Context API finally stopped being an experimental API and became a very useful feature which can now be safely used in production. The times when we had to decide if we will be passing props down from a parent down to the bottom through a few components which do not even use the prop, or use Redux for that instead, are fortunately behind us.

Instead of prop drilling, we can now use Context API to create a Provider with values that we want to make accessible to a child component. In a child component, we can just use a Consumer to access values passed.

Let's start with a simple project to see how Context API works. Open your terminal and run 'npm install -g create-react-app' and then when it is installed, create a new app by typing 'create-react-app context-api'. After the project is created, type 'cd context-api' and then 'npm start'. You should be able to access React app on http://localhost:3000/ and see the standard content of the React app when it is created. We will clean App.js file a little bit as we do not really need everything there. That's how your App.js file should look like at the moment:

import React, { Component } from 'react';
import './App.css'; class App extends Component { render() { return ( <div className="App"> </div> ); }
} export default App;

In the 'src' directory, create a new folder 'components', and then inside, create Header.js file. On Twitter, users can choose their own color scheme so we will build a simple header where we will provide a config for a theme. First, add some dummy content in the Header.js file as well as create a Header.css file with a little bit of styling.

Header.js

import React, { Component } from 'react';
import './Header.css';
const Header = props => { return ( <header className="orange-theme"> <div className="header-container"> <div>Here is our awesome logo</div> <nav> <ul> <li>Home</li> <li>About</li> <li>Profile</li> <li>Help</li> </ul> </nav> </div> </header> )
} export default Header;

Header.css

header { width: 100%; height: 80px;
} .orange-theme { background-color: #FF851B;
} .teal-theme { background-color: #39CCCC;
} .green-theme { background-color: #2ECC40;
} .header-container { display: flex; justify-content: space-between; align-items: center; width: 70%; height: 100%; margin: 0 auto;
} nav ul { display: flex; list-style: none;
} nav ul li { margin: 0 20px;
}

Our default theme color will be orange, but we also have teal and green themes. Of course, we also have to now import Header.js and add it to our App component.

import React, { Component } from 'react';
import './App.css';
import Header from './components/Header';
class App extends Component { render() { return ( <div className="App"> <Header /> </div> ); }
} export default App;

After adding all of this code, you now should have an orange header with logo text and navigation.

header1.png

I know, nothing special, but we are not here to build a beautiful header 😉 We need to create two more files, the first one is config.js. We will put there an object with user's chosen theme. Normally, config like this would be fetched from the server, but for the purpose of this tutorial, this should be enough. In config.js just write:

export default { userTheme: 'teal'
}

The second file is a ThemeContext.js, in which we will create a new context. Create a new folder for it in /src directory called 'context', and after that, create our ThemeContext.js file.

Now is the time for the fun to begin. In ThemeContext.js, create and export a new constant that will hold the context and pass an object with userTheme property, which will default to orange if theme is not provided.

import React from 'react'
export const ThemeContext = React.createContext({userTheme: 'orange'})

The next thing to do is to use a provider to make this theme accessible to child components. In App.js, we have to import the context and then wrap the top div with ThemeContext.Provider. We also need to import our userConfig and pass it as a value to the provider. Here's what your App.js file should look like:

import React, { Component } from 'react';
import './App.css';
import Header from './components/Header';
import userConfig from './config.js';
import { ThemeContext } from './context/ThemeContext';
class App extends Component { render() { return ( <ThemeContext.Provider value={userConfig}> <div className="App"> <Header /> </div> </ThemeContext.Provider > ); }
} export default App;

Import the ThemeContext in the Header.js so that we can use it to get our user config.

import { ThemeContext } from '../context/ThemeContext'; const Header = props => { return ( <ThemeContext.Consumer> ...other content here </ThemeContext.Consumer> )
}

An important fact to remember is that Consumer requires a function as a child, which returns JSX. The value that we passed in the provider is accessible as the first parameter. We will use destructuring to get our userTheme property and use it for the header class.

import { ThemeContext } from '../context/ThemeContext'; const Header = props => { return ( <ThemeContext.Consumer> {({ userTheme }) => ( <header className={userTheme + '-theme'}> ...other content here </header> )} </ThemeContext.Consumer> )
}

If you save your Header.js file, you should see that background color of header did change to teal. That's how you provided a value from a parent to the child component. I know that in this case Header is a direct child of App, and you could just pass it as a prop, but this is just to show how Context API works. If you remove the userTheme property from config, then the background will change to orange, as we provided a default theme when creating the context.

header2.png

Context API is a very interesting and useful feature that can help you avoid passing props through many components. There were even suggestions that now that Context API is not experimental anymore, it will replace a need for state management libraries like Redux.

I personally think that state management libraries will still remain an important part of React applications. In contrast to Context API, state management libraries do offer production tested solutions that help to reason about and maintain the flow of the application and how components communicate with each other.

We can keep our components leaner while having a separate concerns and centralized store with the state. Or maybe let's just create a state management library based on the Context API? We will see what the future will bring as it is hard to forecast what can happen in ever changing trends and technologies.


Tag cloud