REACT Context

Introduction 

According to the React documentation, React context allows us to pass data down the component tree without manually passing props at each level.

Earlier, we had to utilize the render prop pattern with class components, due to which the old Context was a pain to use, and it was always labeled unstable/experimental.

Things are now very straightforward thanks to the introduction of Hooks, notably the useContext Hook.

After you've created a context, all you have to do now is:

const userName = useContext(UserContext);

React published the Context API(Application Programming Interface) as a much-needed solution for state that spans numerous nested components. Regrettably, the context API was a bit cumbersome and difficult to use in class components. With hooks release, the React team opted to rethink how you interact with context and utilize the useContext hook to simplify the code greatly.

What is Prop-drilling?

Prop drilling is the process of moving props from one part of a tree to another in a React application by passing them via elements of the tree that don't require the data but just aid in their passage.

Let us take an example without using {useContext}.

import React from "react";

export default function Application() {
 const name = "Coding Ninjas";

 return <Hello name={name} />;
}

function Hello(props) {
return (
  <div>
    <h1>Hello Everyone!</h1>
    <Greeting name={props.name} />
  </div>
);
}

function Greeting(props) {
return "Welcome to " + props.name;
}

OUTPUT:

Context API

React uses state to store data and props to pass data across components. This is useful for passing simple props between parent and child components as well as handling local state. This system breaks down when you have a global state or props that need to be provided to deeply nested components. With only props and state, you'll have to resort to prop drilling, which entails routing props through several different components for them to reach a single component farther down the hierarchy.

 

The Context API comes into play here. You can provide specific pieces of data that will be exposed to all components nested inside the context using the context API, eliminating the need to transmit this data across each component. It's basically a semi-global state that may be accessed from anywhere within the context.
 

Without transmitting data through props manually, the Context API may be used to communicate data with different components. For example, the Context API is appropriate for the following use cases: theming, user language, authentication, and so on.

To initialize the context: createContext

We will first create the context to use it later for the provider and the consumer.

Example: To create a ‘ContextThemeHere’ for the React application’s theme.

import React from 'react';

// To pass the theme default value as 'light'
const ContextThemeHere = React.createContext('light');
export default ContextHere;

Although the createContext function accepts an initial value, it is not needed.

After you've created your context, it now has two React components: Provider and Consumer, which will be used further.

Create Provider

Providers are used to send a context value to the tree beneath them. Any component rendered inside the Provider, no matter how deep in the tree, can read its value. Let us look at an example:

/*
    To provide the theme default value as 'light' to the 
    components rendered inside Application
*/
<ContextThemeHere.Provider value = "light">
    <Application>
</ContextThemeHere.Provider>

Create Consumer

Consumers are used to determining the worth of a context. As a child, these require a function that gets the current context value and returns a React node:

<ContextThemeHere.Consumer>
    {theme => <span>{value}</span>
     /*The ‘theme’ is the context value that can be used by JSX in 
     this case*/}
</ContextThemeHere.Consumer>

We can have as many consumers as we want for a single context. All consumers are immediately alerted and re-rendered if the context value changes (by altering the ‘value’ prop of the provider <Context.Provider value={value} />).

 

If the consumer isn't wrapped in the provider but still tries to access the context value (through useContext(Context) or <Context.Consumer>), the context's value is the default value argument passed to the createContext(defaultValue) factory function that created the context.

React Hook: useContext

In the React useContext, we no longer need to wrap the JSX in a consumer to use context in a function component. Instead, simply send the context to the ‘useContext’ hook, and it will take care of the rest. Let's look at an example.

const AuthContext = React.createContext({
    authenticated: false, 
    login: () => {}
});

const LoginPanel = props => {
  const authContext = React.useContext(AuthContext);
  return(
    <div className="loginPanel">
      <h1>React Context API</h1>
      <div className="test-details">
        <small>
          <span><strong>User:</strong> CodingNinjas</span>
          <span><strong>Password:</strong> 12345</span>
        </small>
      </div>
      <form>
        <input type="text" name="user" size="30" placeholder="Enter Username" />
        <input type="text" name="password" size="30" placeholder="Enter Password" />
        <button onClick={authContext.login}> Login </button>
      </form>
    </div> 
  );
}

const LoginConfirmation = () => { 
  const authContext = React.useContext(AuthContext);

  return(
    <div className="confirmationBox">
    { authContext.authenticated ? <p className="confirmation">Login successful!</p> : <p><em>Wrong input! Try logging in again</em></p> }
    </div> 
    );
}  

class Application extends React.Component {
  
  state = {
    authenticated: false
  }
  
  loginHandler = ( event ) => {
  
    event.preventDefault();
    
    var sampleUser = {
      name: 'CodingNinjas',
      pass: '12345'
    }
  
    var user     = document.querySelectorAll("[name=user]")[0];
    var password = document.querySelectorAll("[name=password]")[0];
  
    if ( user.value === sampleUser.name && password.value === sampleUser.pass ) {
      this.setState({ authenticated: true }); 
    } else {
      this.setState({ authenticated: false }); 
    }
    user.value = '';
    password.value = '';
}
  
render() {
    return (
        <AuthContext.Provider value={{authenticated: this.state.authenticated, login: this.loginHandler }}>
          <LoginPanel />
          <LoginConfirmation />
        </AuthContext.Provider> 
    );
  }
}

ReactDOM.render( <Application />, document.body );

OUTPUT:

We will now enter the ‘username’ and the ‘password’ as the input:-

 

We will now click on 'LOGIN,' and the output will be like this:-

Hence, we get the alert as ‘Login successful!’.

Using react useContext, we can remove all of the complex nestings and cut away all of the consumer portions of the context using useContext. Now, context operates like any other function in that you call it, and it returns the values it contains for you to use later in the code. This dramatically simplifies context-related code and makes working with context a lot more fun.

Which one to choose: Context or Redux?

Is it true that context takes away Redux? 

No. It isn't the case. As we've seen, they're two very distinct tools, and comparing them is frequently the result of a misunderstanding of what they are.

Context can be used as a state management tool, but that wasn't the purpose, and you would have to make some effort to make it fit your preferences.

While you're at it, you should keep in mind that there are already a lot of state management solutions available that will help you out in case you get stuck.

It was rather complex in my experience with Redux for something that is now easy to handle with context. However, keep in mind that their routes only cross here: prop-drilling and global state management. This is only a small part of what Redux is capable of.

Redux and context should not be two concepts strung together with "vs." in a just and fair world; instead, they should be considered as things that function together. Context API is for small applications where state changes are minimal. In comparison, redux is preferred for larger applications where there are high-frequency state updates. We can use context to avoid prop-drilling and can use Redux for global state management. 

Frequently Asked Questions

  1. What do you mean by React context?

 

React's context allows you to exchange information with any component by keeping the information in a central place and granting access to any component that wants it (usually, you can only pass data from parent to child via props)
 

2. Which problem is solved by React Context API?
 

Prop-drilling is solved by React context API. It's likely happened to you if you've worked on a React.js app, even if you're unfamiliar with the word. Prop drilling is the process of transferring data from component A to component Z through various layers of React components. The component will receive props indirectly, and it will be up to you, the React Developer, to make sure everything works well.

 

3. What is meant by a provider?

 

The provider performs the function of delivery service. When a customer requests anything, the provider locates it in the context and delivers it to the appropriate location.

Key Takeaways

In this blog, we went over the fundamentals of React context. We also learned more about the React context API. The Context API was created to address several issues in React apps, the most notable of which being prop-drilling. In addition, we learned how to use the useContext hook.

Enroll in our Advance Front-end Web Development Course- React.js to deeply understand the concept of React context in Web Development. 
 

Credits: GIPHY

 

Happy Developing!

Was this article helpful ?
0 upvotes

Comments

No comments yet

Be the first to share what you think