With React 16.3 recently released I thought it was time to take a look at the new context API. The new context API does what it says on the tin - it allows components to get data from a context rather than from props. It prevents having to pass props down through child component through child component … i.e. “prop drilling”.

So, let’s give this try for allowing a couple of components to consume data about a tenant in a multi-tenant app. The first child component will show the name of the tenant. The second child component will show a form capturing a name and age. Whether the age is captured depends on a promptForAge flag in the tenant.

Container component

The shell of our container component is below. It gets the tenant data from a web service and puts it in its state. We are referencing child components Title and ContactForm but we aren’t using the new context API yet.

class App extends Component { state = { tenant : null } componentDidMount ( ) { fetch ( "http://localhost:21246/api/tenant" ) . then ( ( response ) => { return response . json ( ) ; } ) . then ( data => { this . setState ( { tenant : data } ) ; } ) . catch ( error => { console . log ( error ) ; } ) ; } render ( ) { const { tenant } = this . state ; return ( { tenant && < div className = " container " > < Title /> < ContactForm /> </ div > } ) ; } }

Let’s create our context. We’ll call it TenantContext .

const TenantContext = React . createContext ( ) ;

Now let’s specify the context provider around the child components in our container component passing in the tenant as the value:

render ( ) { const { tenant } = this . state ; return ( < TenantContext.Provider value = { tenant } > { tenant && < div className = " container " > < Title /> < ContactForm /> </ div > } </ TenantContext.Provider > ) ; }

Title component

The context is now setup nicely in our container component. This is our Title component without consuming TenantContext :

function Title ( ) { return < h1 > { } </ h1 > ; }

So, let’s consume TenantContext using the render props pattern:

function Title ( ) { return ( < TenantContext.Consumer > { tenant => < h1 > { tenant . name } </ h1 > } </ TenantContext.Consumer > ) ; }

ContactForm component

Moving on to our ContactForm component, we again consume TenantContext using the render props pattern. We use tenant.promptForAge to conditionally render the age input. In our simple example, we only submit the details to the console.

class ContactForm extends React . Component { state = { name : "" , age : 0 } ; handleSubmit ( e ) { console . log ( this . state ) ; e . preventDefault ( ) ; } render ( ) { const { name , age } = this . state ; return ( < TenantContext.Consumer > { tenant => ( < form onSubmit = { e => this . handleSubmit ( e ) } > < p > Enter your details ... </ p > < div className = " form-group " > < label htmlFor = " name " > Name </ label > < input type = " text " className = " form-control " id = " name " value = { name } onChange = { e => this . setState ( { name : e . target . value } ) } /> </ div > { tenant . promptForAge && ( < div className = " form-group " > < label htmlFor = " age " > Age </ label > < input type = " number " className = " form-control " id = " age " value = { age } onChange = { e => this . setState ( { age : e . target . value } ) } /> </ div > ) } < button type = " submit " className = " btn btn-primary " > Save </ button > </ form > ) } </ TenantContext.Consumer > ) ; } }

Wrap up

The new react Context API is super simple to use and is a great alternative to “prop drilling” for sharing state across multiple components.