CodeNewbie Community

Cover image for Learn React Context by building a dead simple wallet app (For beginners)
Ridhik Govind
Ridhik Govind

Posted on

Learn React Context by building a dead simple wallet app (For beginners)

If you are a beginner to React and you have been using props to pass data from one component to another then this article is for you to help level up your context game. Also this is my FIRST post on the amazing codeNewbie community. Yay !

P.S - This article is mainly focused on absolute beginners and thats why I have tried to explain things in details - its gonna be pretty long. It is also assumed that you have the basic knowledge of how React Hooks work.

Why use React Context ?

You see there is a concept called as 'prop-drilling' in React . Basically it means passing down certain data from a parent component to another through props. React context is an easier alternative to this method.(explained in detail later on)

What are props ?

Imagine your own parents, see they must be having some kind of special characteristics. It could be the color of the eyes, skin color, shape of the nose etc. Similarly, in React each parent component has characteristics( or lets call it properties or even a better word would be - props) can be passed down to the children in case we want to make changes to the child components based on the parent components.

So what's with the whole 'props' my friend ?

Let's understand this with the help of an example.

Step 1: Create a parent component. Now also notice that we have created some styles that the parent wants to pass to its child.

import React from "react";

style = {
color: "red"
}

function Parent() {
  return (
    <div>
      Parent component
    </div>
  );
}

export default Parent;
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a Child component.

import React from 'react'

function Child() {
  return(
    <div>
      Child component
    </div>
  )
}

export default Child
Enter fullscreen mode Exit fullscreen mode

Step 3: Now comes the important part - Passing props. First of all in your parent component import the Child component and wrap the child inside the parent. Second, pass the "style" variable as the props(named style) to the child component. Here's how you can do do that:

//Parent.js

function Parent() {
  return (
    <div>
      Parent component
+     <Child style={style} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Now the only part left is grabbing this passed prop from the child component's side and applying the style to the child element.

  • First, using the destructuring method, we extract the "style" prop from the parent. Now this is available as a variable we can use anywhere. e.g:
function Child({ style }) {
  return <div style={style}>Child component</div>;
}
Enter fullscreen mode Exit fullscreen mode
  • Second, just apply the style to the child element, that's it voila ! The text in your element in now Red.

Here's how the final code for both parent and child components will look like:

https://codesandbox.io/s/react-context-parent-child-props-example-1f8kl?file=/src/App.js

But the title says we were going to build a dead simple wallet app? Where is that ?

So the reason I explained using the prop method this extensively is because first we won't be jumping into building a wallet using React Context. Instead, we will go through some base model code of how this wallet should be Using props and then we shall look at how easy-peasy it is using React context.

Let's begin >>>

METHOD 1: BASE CODE FOR WALLET - (USING PROPS)

Story time : There are 3 banks - Paytm, Sbi and Axis. These 3 banks they regularly deal with money. But the only problem is, if Paytm(1st bank) wants to send money to Axis(3rd bank), Paytm can ONLY do this by first transferring the money to Sbi and then Sbi will transfer the money to Axis. ( I know normally, this is not the case, but in our example we assume it this way ).

So the main way these three banks transfer money through each other is through 'props' - yep, the same props we have explained above.

GOAL: Our goal is to transfer money from Paytm to Axis bank by having Sbi as a middle group just for passing the props and nothing else. You can think Sbi as more of a bridge/agent here.

Alt Text

Step 1: Create 3 components namely - Paytm.js, Sbi.js, Axis.js.

Step 2: Let's talk about Paytm.js first. Here you go:

import React, { useState } from "react";
import Sbi from "./Sbi";
function Paytm() {
  const [amount, setAmount] = useState(200);

 //send PaytmName money to Axis bank
  return (
    <div>
      <h2>Paytm</h2>
      <Sbi amount={amount}/>
    </div>
  );
}

export default Paytm;
Enter fullscreen mode Exit fullscreen mode

Explanation: So here have created a Paytm.js component. Inside there is a state hook that is having a default 'amount' value of 200. But could you just look at our goal: It says 'transfer this amount 200 to Axis bank using Sbi as an agent'. So we pass this 'amount' state varibale to the prop 'amount' (you can name your prop anything you want but for the sake of simplicity I'm naming it amount).

Step 3: Time for Sbi to act as an agent.

import React from "react";
import Axis from "./Axis";

function Sbi({amount}) {
  return (
    <div>
      <h2>Sbi</h2>
      <Axis amount={amount}/>
    </div>
  );
}

export default Sbi;
Enter fullscreen mode Exit fullscreen mode

Explanation: Remember the Parent-Child example I explained from above ? And how I explained the whole dealing with the 'prop', 'destructuring' etc ? Here is the exact same thing we are doing. Here, Sbi extracts the prop passed from Paytm and then passes it as the props to its child element (Axis).If you havn't understood this part, don't worry, just go through the Parent-Child example.

Step 4: Last and final part - creating our Axis.js.

import React from "react";

function Axis({amount}) {
  return (
    <div>
      <h2>Axis received {amount} from Paytm through sbi by way of props</h2>
    </div>
  );
}

export default Axis;

Enter fullscreen mode Exit fullscreen mode

Explanation: Same concepts applied - you destructure the value from the parent of Axis i.e Sbi and then you use the variable inside the text. Now if you are coding along with me until now, you will notice that the amount value of 200 has been Successfully been transferred from Paytm -> Axis Bank. This is how you pass a value through props MISSION COMPLETED.

Have a look at the code: https://codesandbox.io/s/react-bank-exampleusing-props-xpxv6?file=/src/Axis.js:0-192


METHOD 2: BUILDING A WALLET (USING REACT CONTEXT)

Alt Text

So this is basically what we will be building, I know its not much of a wallet app but there's a lot going on here.

Understanding React Context

'Context' in english language simply means 'any data/information that has been set already which can help us understand the current situation'. In React, creating a context simply means creating a universal store of values and grabbing them whenever we need.
The rule that React Context follow is: Store once, use anywhere. How it works is because React context has two objects - a Provider and a Consumer. A Provider, as the name suggests is where we have to store the data and a Consumer is the one who uses this data. So in our example, if Paytm is the Provider, then both Sbi and Axis are consumers. But when we look at our goal, then which one do you think our consumer should be ? Axis bank of course !

Goal: Send money from Paytm -> Axis bank without transferring the money through Sbi by using React Context.

Step 1: We start by creating MyContext.js file:

//MyContext.js

import React from "react";

const MyContext = React.createContext();

export default MyContext;
Enter fullscreen mode Exit fullscreen mode

Explanation: In React, the context object comes pre-loaded. So if we need to make use of context, we have to initialize context by creating React context object using createContext and then storing this in a variable called 'MyContext', then exporting it.

Step 2: Create a Context Provider inside Paytm.js

//Paytm.js

import React, { useState } from "react";
import Sbi from "./Sbi";

import Total from "./Total";
import Balance from "./Balance";

import MyContext from "./MyContext";

const style = {
  background: "black",
  color: "red",
  padding: "0.5rem",
  display: "grid",
  gridTemplateColumns: "1fr 1fr"
};

 function Paytm() {

  const [amount, setAmount] = useState(200);
  const [total, setTotal] = useState(500);
  const [balance, setBalance] = useState(null);

  //Goal: send Paytm money to Axis bank without the passing the money through Sbi

  return (
    <MyContext.Provider value={{
        amount,
        total,
        setTotal,
        balance,
        setBalance,

      }}>
      <div>
      <div className="paytmWallet" style={style}>
          <Total />
          <Balance />
      </div>
        <h2>Paytm</h2>
        <Sbi />
      </div>
    </MyContext.Provider>
  );
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • First, we import the MyContext variable from MyContext.js. Why ? So that we can create a Provider.
  • Create a Provider object using MyContext as shown above. One important thing to notice here is that, you have to wrap the child components inside the Provider so that each child has access to the data from the central store of the Provider. E.g Since Axis is a child of Sbi, we have to wrap Sbi around Paytm's Provider.
  • Next, we create some state hooks with some default values that we will pass as 'props' to the Provider. This 'props' that we are passing is available to all the child elements down the road that is wrapped inside this Provider. e.g Since Sbi is wrapped inside, Sbi.js has access to it, so does Axis.js.
  • We have also created a small wallet section that is going to display our Paytm wallet details with some basic styling.

Step 3: We create the Sbi.js component which has nothing but its child component Axis.js

//Sbi.js

import Axis from "./Axis";

function Sbi() {
  return (
    <div>
      <h2>Sbi</h2>
      <Axis />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Create Axis.js component. This is where we have to use useContext to grab the data that we have passed as props to the Provider.

  • In React, we can either follow one approach which is creating a Consumer object from 'MyContext'. But here we will be following the 'useContext' approach.
  • useContext is a hook (just like useEffect and useState) that is used to grab the prop values from the nearest Provider. It works by accepting the context object i.e MyContext and then returning the prop value of the nearest Provider i.e Paytm.
import React from "react";
import MyContext from './MyContext'

function Axis() {
  const value = React.useContext(MyContext)
  return (
    <div>
      <h2>Axis received <span style={value.amountStyle}>{value.amount}</span> from Paytm through sbi by way of useContext</h2>
    </div>
  );
}

export default Axis;
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • As you can see, the variable 'value' contains all the values of the 'value' prop that we have passed in the Provider. So in order to display the amount that has been transferred, you can use {value.amount}.
  • But it is not only state hooks that we can pass as 'props' to the Provider, we can even pass objects. E.g If we need to apply a certain style, we the pass the object 'amountStyle' and in Axis we can use it by way of {value.amountStyle} and this will apply all the styles as usual. See how easy it is than doing 'prop-drilling' !

In paytm.js pass in the following 'amountStyle' below 'style' object:

const amountStyle = {
  background: "black",
  color: "red"
};
Enter fullscreen mode Exit fullscreen mode

Now pass 'amountStyle' to the list of value props of the Provider.

Step 5: This step will be one of the easist, because you already have an idea of how Context works now.
This step involves creating a 'Total' and 'Balance' component:

//Total.js

import React from 'react'
import MyContext from './MyContext'

function Total() {
  const value = React.useContext(MyContext)
  return (
    <div className="total">Total:{value.total} </div>
  )
}

export default Total;
Enter fullscreen mode Exit fullscreen mode
//Balance.js

import React from 'react'
import MyContext from './MyContext'

function Balance() {

  const value = React.useContext(MyContext)

  return (
    <div className="Balance" >Balance:{value.total - value.amount} </div>
  )
}

export default Balance;
Enter fullscreen mode Exit fullscreen mode

Explanation: While the total value remains the same, the balance value is changed dynamically according to the amount that has been transferred from 'Paytm wallet' to 'Axis' bank.

Try changing the 'amount' value from 200 to 300. You can notice that the 'balance' amount has changed - this is because we are changing the state of 'amount' in Paytm (Provider) also.

At the end the whole code would look something like this:

https://codesandbox.io/s/react-bank-wallet-using-usecontext-final-u8guh?file=/src/App.js

Side note: So if you looked at the above code, and you are thinking "What would I gain by just passing values around, I don't think I will be using this often !".
I used to think like this, until I started building bigger applications and passing data from one component to another can turn out to be a total mess. So if you are building a really small app - go on and use the prop method. But, if it has like components that are nested real deep - don't even think twice, use Context.It can be confusing at first, but you'll get the hang of it.

What we have learned so far:

  • Meaning of props through a 'Parent-Child' component example.
  • Prop-drilling (when to use it and when not to use it)
  • Understand how destructuring works(refer MDN docs for more)
  • How to use React context - Provider and Consumer concept
  • How to use the 'useContext' hook to grab data from the Context Provider easily by way of creating a wallet app.

As always the mandatory Gif is here:
 after using react context for the first time
This will be you after using React Context for the first time.

Heya everyone, I am Ridhik - I love working with React and also sharing the most difficult problems I have faced with simple explanations suitable for absolute beginners. Please feel free to get in touch with me on Twitter if you have any doubts.
Ciao !

Discussion (0)