My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more

Props and Context API! Which one to use when?

Priyansh Maurya's photo
Priyansh Maurya
·Aug 9, 2021·

4 min read

React is one of the most popular JavaScript libraries for building user interfaces today. React has a different approach of data flow & manipulation than the other frameworks, which makes it quite different from other frameworks and that’s why it can be difficult at the beginning for the people to understand some concepts like props, state, context and so on.

What are Props in React?

React is a component-based library that helps us divide the UI into small reusable pieces, which we call a component. So, in order to pass data or to communicate between the components, we make use of Props. Prop (stands for property) is a special object that React uses to transport data from one component to another.

Don't need this

Now, the data in props are read-only meaning it cannot be changed by the child who is consuming the data. Thus it is a unidirectional flow (one way from parent to child). We can however pass data from child to parent making use of the function passing it via props.

Let's understand this with an example.

const App = () => {
  return(
    <Parent color= "blue"/>
  );
}

const Parent = (props) => (
  <Child color= {props.color} />
)

const Child = (props) => (
  <GrandChild color= {props.color} />
)

const GrandChild = (props) => (
  <p>Color: {props.color}</p>
)

In the above code, we have used color props in the Parent component and have passed that props to all component (top to down) without checking if it is required by the child components or not.

Prop Drilling

prop-1-304x300.png

Refer to the above UI Tree. Suppose the parent (i.e. the root) component 1 wants to send data to one of its deeply nested child component i.e. component 6. So, by using props, we can't pass down a property directly to the target component. This is because React follows the rule where properties have to flow down from a parent component to an immediate child component.

This means we can’t skip a layer of child components when sending a property and the child components can’t send property back up to a parent as well due to it's unidirectional flow.

props2-304x300.png

This is Prop drilling, which refers to the passing of the data from the parent to all the nested children in the React Tree, that do not necessarily need that data.

Prop Drilling It's literally like drilling! Prop Drilling

Since the props can only be passed from parent components, they cannot be changed. This makes them immutable and dumb.

Context API

As per the React docs, Context provides an awesome way to pass data through the component tree without having to pass props down manually at every level in our application, as the data is available inside the Context which is accessible from all child components.

Context

To be more clear, this provides a way for you to make values available to all components of your application, no matter how complicated your application is. So, you should be well aware of all those values, that you are going to use throughout your application.

image.png

Notice the clear difference between moving values to the context vs passing it from component to component.

How does this context API work?

The Context object is a special type of React object that can be used to create and share data. It has two component: Provider and Consumer. The provider is used to create new context objects, while the consumer is used to access or consume values from those contexts.

Let's understand this with an example

import React from 'react'

const CounterContext = React.createContext(0)

const Parent = () => {
    const [counter, setCounter] = React.useState(0)

    const increment = () => setCounter(counter + 1)

    return (
        <CounterContext.Provider value={{ counter, increment }}>
            <DisplayCounter />
            <IncrementCounter />
        </CounterContext.Provider>
    )
}

const DisplayCounter = () => {
    const { counter } = React.useContext(CounterContext)

    return <div>{counter}</div>
}

const IncrementCounter = () => {
    const { increment } = React.useContext(CounterContext)

    return (
        <div>
            <button onClick={() => increment()}>increment</button>
        </div>
    )
}

Here, we are using the 'CounterContext' provider to share the context between multiple components. The 'DisplayCounter' is retrieving the counter state and displays it value, while 'IncrementCounter' is retrieving the increment action from the context instead.

Conclusion

  • Context API is always a good choice when the data stored does not have frequent updates like dark/light mode (theme), profile picture details, account details, etc.
  • React is already fast and doesn’t need many optimizations, Most of the case prop drilling can be also a good choice to consider as it is easy from an implementation perspective
  • Try to keep the state of the app as close as to the render component.
  • There is no proper guide on whether you should go with prop drilling or context API, Just validate your code in terms of necessity, whether it is required to do or no and then proceed.