DEV Community

Cover image for Getting Started With React Context API - A Deep Dive
punya2004
punya2004

Posted on

Getting Started With React Context API - A Deep Dive

So it’s my first blog and had a thought about posting something that could be helpful for React-developers beginners like ME. So I’ve been working in react for last 3–4 months and one rookie problem that most of us face while building your own first big project.

What is Context API?

Context API is a way to enable components to share some data without explicitly passing via each component manually. Context is like a global object to the React component sub-tree.

Why we need Context API ?

Nearly every developer knows that React components are structured like a tree. There is one root node where all the components are connected. In this tree structure, the data flows in only one direction — from top to bottom.

The problem of prop drilling arises when you create a tree structure of several components and the state created in higher level component you try to use it in lower level components. In such case you need to pass that as prop through all component levels, which is not a good practice.

One line definition would be “API which is created in React itself and provides a way to pass props down the whole tree component at every level.”

There are different methods to use context in you React-app, Here is how I use it :

1.First I created A StateProvider.js file which integrated my app to context API

StateProvider.js

import React, { createContext, useContext, useReducer } from "react";

export const stateContext = createContext();

export const StateProvider = ({ reducer, initialState, children }) => (

    <stateContext.Provider value={useReducer( reducer, initialState )}>
        {children}
    </stateContext.Provider>
)

export const useStateValue = () => useContext(stateContext);

Enter fullscreen mode Exit fullscreen mode

2.Then I used The StateProvider in index.js allowing context to be used in App component.

Index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import Reducer, { initialState } from './Reducer';
import { StateProvider } from './StateProvider';

ReactDOM.render(
  <React.StrictMode>
    <StateProvider initialState={initialState} reducer={Reducer}>
    <App />
    </StateProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

Enter fullscreen mode Exit fullscreen mode

Now in StateProvider.js I created context using createContext() method in react, And using it in useContext method you can can read the current value of states through the components. Then you create StateProvider function where you pass parameters like reducer , initialState and children props which will be root(App.js) component (because we need to use the state through out all the tree).

So now in index.js I wrapped the component with provider I just created as StateProvider passing it intialstate and reducer from reducer.js as created in the code below.

3.Then I created reducer.js file where I defined intialState and reducer function.

reducer.js

export const initialState = {
    user: null,
}

function Reducer (state, action) {
    console.log(action)
    switch(action.type) {

        case 'SET_USER':
            return {
                ...state,
                user: action.user
            }
         default:
            return state;
        }
}

export default Reducer;
Enter fullscreen mode Exit fullscreen mode

4.Then using useStateValue() i.e. useContext() I was able use my state anywhere I want,

App.js

import React, { useEffect } from 'react';
import Login from './Login';
import { auth } from './firebase/config';
import { useStateValue } from './StateProvider';

function App() {

  const [{ user }, dispatch] = useStateValue();

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((authuser) => {
      if(authuser){

        dispatch({
         type: 'SET_USER',
          user: authuser
        })
      } else{    
        dispatch({
          type: 'SET_USER',
          user: null
        })
      }
    })
    return () => {
      unsubscribe();
    }
  }, [])

  console.log("user is...", user)
Enter fullscreen mode Exit fullscreen mode

Here the initialState is an object initializing all the variables that you want to use in tree and reducer function will take care of updating the DOM of that state.

Now in App.js using useStateValue variable created in StateProvider.js I accessed the current value of user. useStateValue i.e. useContext returns an array where first value is state i.e. user written as {state} and second is dispatch method which will dispatch the new value of state and type of action. Since it need to be performed only one time when page renders I use dispatch method in useEffect hook.

Here I set type as “SET_USER” and value of user as authuser that I got from firebase . So now it passes type as action.type and user as action.User which is updated in “SET_USER” case of switch in reducer function. I updated the user state using rest operator returning previous value and updating only user.

Top comments (0)