Introduction To Render Props And Context In ReactJS

Introduction

In the previous article, we have learned about Higher-Order Components in React along with its usage. In this article, we will go through Render Props and the concept of Context in React. 

Render Props

Render Props in React is something where a component’s prop is assigned a function and that is called in the render method of the component. Calling the function will return a React element or component.

Third-party libraries like React Router and Downshift uses this approach. A render prop is a function prop that the component uses to know what to render. Through this, we can also pass a state to another. 

Let’s see a demo. Create a Movement.js file and code as below,

import React, { Component } from 'react'  
  
export class Movement extends Component {  
  
    constructor(props) {  
        super(props)  
      
        this.state = {  
                x:0,  
                y:0  
        }  
    }  
      
    onMouseMove =(event) => {  
        this.setState({  
            x:event.clientX,  
            y:event.clientY  
        })  
    }  
  
    render() {  
        const{x,y} = this.state  
        return (  
            <div style={{height : '100%'}} onMouseMove={this.onMouseMove}>  
                <h1> The current mouse position is ({x},{y})</h1>  
            </div>  
        )  
    }  
}  
  
export default Movement  

Now add this Movement.js in App.js,

import React from 'react';  
import './App.css';  
import './css/custom.css';  
import Movement from './components/Movement'  
  
function App() {  
  return (      
    <div>  
      <Movement></Movement>  
    </div>  
  );  
}  
  
export default App;  

The above code will display output as below.

Render Props And Context In ReactJS

Now let’s go further with the demo, we will create a component named Monkey in which on moving the mouse, the monkey will also move following the banana.

Let’s see the demo. Change the code of Movement.js as below,

import React, { Component } from 'react'  
import PropTypes from 'prop-types'  
  
export class Movement extends Component {  
  
    static propTypes = {  
        render: PropTypes.func.isRequired  
    }  
  
    state={x:0,y:0}    
      
    onMouseMove =(event) => {  
        this.setState({  
            x:event.clientX,  
            y:event.clientY  
        })  
    }  
  
    render() {          
        return (  
            <div onMouseMove={this.onMouseMove}>  
               {this.props.render(this.state)}  
            </div>  
        )  
    }  
}  
  
export default Movement  

Now, create Monkey.js with the below code.

For below, we also need 2 images of monkey and banana respectively which are uploaded in the source code of Demo2.

import React, { Component } from 'react'  
import monkey from '../images/monkey.jpg'  
import banana from '../images/banana.jpg'  
  
export class Monkey extends Component {  
    render() {  
        const{x,y} = this.props.Movement  
  
        return (  
            <div>  
                <img src={monkey} alt='monkey' style={{position:'relative',left:x,right:y,height:150}}></img>                      
                <img src={banana} alt='banana' style={{position:'relative',left:(x+10),right:(y+10),height:30}}></img>                      
            </div>  
        )  
    }  
}  
  
export default Monkey 

Now, in the final step, call Monkey.js in App.js.

import React from 'react';  
import './App.css';  
import './css/custom.css';  
import Movement from './components/Movement'  
import Monkey from './components/Monkey'  
  
function App() {  
  return (      
    <div>           
      <Movement render={({x,y}) =>  (  
        <Monkey Movement={{x,y}}/>  
      )}/>  
  
    </div>  
  );  
}  
  
export default App;  

This will display the output as below.

In the above image, on moving the mouse, the monkey will also move. The above demo is quite interesting and lets us allow to animate other animation can be created using react-motion API. 

Now, we will see the concept of Context in ReactJS. 

Context

The Context in React.js is the concept to pass data through a component tree without passing props down manually to each level. 

In basic React application, to pass data from parent to child is done using props but this is a heavy approach if data needs to be passed on multiple levels like passing username or theme required by most of the components in the application.

Context lets you provide the functionality to share values among components without explicitly passing props through every level of the component tree. Mainly context is used when the current authentication, themes, or preferred language need to be passed to the child levels when not required to pass props. 

To get data using context we need to follow 3 steps,

  1. We need to first create the context.
  2. Then we need to provide value to the context.
  3. Lastly, we need to consume the value of context.

Now let’s have a look at the demo, For Example – In the current demo, we will see how to use username in child component using context.

First, we will create a new file namely UserContext.js. This is the first step where we are creating context

import React from 'react'  
  
const UserContext = React.createContext()  
  
const UserProvider = UserContext.Provider  
  
const UserConsumer = UserContext.Consumer  
  
export {UserProvider,UserConsumer}  

Now, we will create a nested structure in which I will create 3 level components Master Component -> Home Component -> Profile Component. App.js in which we will execute the second step we need to provide value to consumer,

import React from 'react';  
import './App.css';  
import './css/custom.css';  
import MasterComponent from './components/MasterComponent'  
import { UserProvider } from './components/UserContext';  
  
function App() {  
  return (  
    <div className="App">  
      <UserProvider value="New User">  
        <MasterComponent />  
      </UserProvider>  
    </div>  
  );  
}  
  
export default App; 

MasterComponent.js 

import React, { Component } from 'react'  
import HomeComponent from './HomeComponent'  
class MasterComponent extends Component {  
    render() {  
        return (  
            <div>  
                <HomeComponent/>  
            </div>  
        )  
    }  
}  
  
export default MasterComponent  

Now second level component is named HomeComponent.js 

import React, { Component } from 'react'  
import ProfileComponent from './ProfileComponent'  
  
class HomeComponent extends Component {  
    render() {  
        return (  
            <div>  
                <ProfileComponent/>  
            </div>  
        )  
    }  
}  
  
export default HomeComponent  

And third level Component named ProfileComponent in which we are going to consume context value

import React, { Component } from 'react'  
import { UserConsumer } from './UserContext';  
  
class ProfileComponent extends Component {  
    render() {  
        return (  
           <UserConsumer>  
               {  
                   (username) => {  
                       return <div>Hello {username}</div>  
                   }  
               }  
           </UserConsumer>  
        )  
    }  
}  
  
export default ProfileComponent

Now the output will be displayed as below,

Render Props And Context In ReactJS

If in UserContext.js while creating context we will define default value and if in case we don’t provide any value in the component then it will take default value from UserContext,

import React from 'react'      
const UserContext = React.createContext('Guest')      
const UserProvider = UserContext.Provider      
const UserConsumer = UserContext.Consumer      
export {UserProvider,UserConsumer}   

And App.js code will be as below,

import React from 'react';  
import './App.css';  
import './css/custom.css';  
import MasterComponent from './components/MasterComponent'  
import { UserProvider } from './components/UserContext';  
  
function App() {  
  return (  
    <div className="App">  
      {/* <UserProvider> */}  
        <MasterComponent />  
      {/* </UserProvider> */}  
    </div>  
  );  
}  
  
export default App; 

The output will be as follows,


Render Props And Context In ReactJS


While using context we can only pass one value, for multiple values we need to use multiple context. 

There is one more way to access context value using Context Type property. 

First, we need to export UserContext from UserContext.js file,

import React from 'react'    
const UserContext = React.createContext('Guest')      
const UserProvider = UserContext.Provider      
const UserConsumer = UserContext.Consumer      
export {UserProvider,UserConsumer}    
export default UserContext     

Now we will consume context value using contextType in HomeComponent.js

import React, { Component } from 'react'  
import ProfileComponent from './ProfileComponent'  
import UserContext from './UserContext'  
  
class HomeComponent extends Component {  
    render() {  
        return (  
            <div>  
                Home Component {this.contextType}  
                <ProfileComponent/>  
            </div>  
        )  
    }  
}  
  
HomeComponent.contextType = UserContext  
  
export default HomeComponent  

The output will be as below,


Render Props And Context In ReactJS

Accessing multiple context values,

import React from 'react'      
const UserContext = React.createContext('Guest')    
const ThemeContext = React.createContext('theme')    
const UserProvider = UserContext.Provider    
const UserConsumer = UserContext.Consumer    
const ThemeProvider = ThemeContext.Provider    
const ThemeConsumer = ThemeContext.Consumer    
export {UserProvider,UserConsumer,ThemeConsumer,ThemeProvider}    
export default UserContext    

and using it in App.js,

import React from 'react';  
import './App.css';  
import './css/custom.css';  
import MasterComponent from './components/MasterComponent'  
import { UserProvider,ThemeProvider } from './components/UserContext';  
  
function App() {  
  return (  
    <div className="App">  
      <UserProvider value="New User">  
        <ThemeProvider value="red">  
        <MasterComponent />  
        </ThemeProvider>  
      </UserProvider>  
    </div>  
  );  
}  
  
export default App; 

Now consuming value of ThemeProvider in ProfileComponent.js file,

import React, { Component } from 'react'  
import { UserConsumer,ThemeConsumer } from './UserContext';  
  
class ProfileComponent extends Component {  
    render() {  
        return (  
           <UserConsumer>  
               {  
                   username => (  
                    <ThemeConsumer>  
                    {color => (  
                         <div style={{ color: color }}>Hello {username}</div>  
                    )}           
                    </ThemeConsumer>         
               )}  
           </UserConsumer>  
        )  
    }  
}  
  
export default ProfileComponent  

The output will be displayed as below,

Render Props And Context In ReactJS

Limitation of Context 

  1. Context can only be used with the class component.
  2. Using context type only a single context value can be accessed. For accessing multiple values, we will need to use nested consumer context.

Summary

In this article, we have learned about the concept of Render Props and Context and its usage in React.

Now in the next article, we will learn about some advanced concepts of HTTP and how Get and Post methods are used in React to fetch data from Server.

Any question or feedback or suggestion, please do comment and let me know.

2 comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s