DEV Community

Cover image for Props Drilling In React?
Akram Narejo
Akram Narejo

Posted on

Props Drilling In React?

  • what's props drilling?
  • why to avoid it?
  • How to dot that?

We are going to answer above questions to know about props drilling.

What's props drilling?

props drilling
Passing props within a tree of components is known to be props drilling. Tree of components means when you pass prop from the root component App to the parent component Header of the child component Search.

App(props) --> Header(props) --> Search(props)

code for above example, shows how placeholder text is set upon the prop passed from root component.

import React from 'react'

export default function App(){
   return(
       <div>
        <Header text="Search Movie..." />
       </div>
   )
}
function Header(props){
    return(
        <header>
            <Search text={props.text} />
        </header>
    )
}
function Search(props){
    return(
        <nav>
            <input 
                type='text'
                value=''
                placeholder={props.text}
            />
        </nav>
    )
}
Enter fullscreen mode Exit fullscreen mode

keep drilling until you reach the bottom.

Why to avoid?

Before knowing the answer, look at the following picture.
Dolls
It seems like every next doll is the child of previous doll, and you can hide all the dolls under the largest doll(root).

What if we want to put the coins in the last doll or in between? here's the catch! we will open the every doll until we open the wanted doll.
So, is the case with components that to change the props in last component we will pass props through every parent component and re-render it. which is quite expensive. that's why we need to avoid this props drilling.

How to avoid?

hmmmm, how to avoid? Well what the logic says is that there should be a global value which must be accessed wherever wanted, right! That's how it is also resolved.

Need 3 things

  • Context component
  • Provider
  • Consumer

Context API is available to help us to provide and consume the context. Components accessing context will only be re-rendered.
Context component will be created by a built-in function of React React.createContext() function by default takes a value, whatever you provide it.
Context API vs props drilling

Create context component

Make a new file, then export and import it.

const Context = React.createContext('default value')
export default Context 
Enter fullscreen mode Exit fullscreen mode

Providing

import the context first, then provide to component you want, suppose we are providing to Header component.

//import Context
<Context.Provider value='Search Movie...'>
   <Header />
</Context.Provider>
Enter fullscreen mode Exit fullscreen mode

Consuming

well context can be consumer by two way, either by React.Consumer or useContext() hook.
let's see the both

Context.Consumer

//import Context first, if it's a separate file.
<Context.Consumer>
{context => <input type='text' value='' placeholder={context} /> }
</Context.Consumer>
Enter fullscreen mode Exit fullscreen mode

useContext() hook

you have to import {useContext} or use as React.useContext, it takes Context as an argument and returns the value.

<input type='text' value='' placeholder={useContext(Context)} />
Enter fullscreen mode Exit fullscreen mode

Complete code

It's a functional component code so I have used hook.

import React, {useContext} from 'react'

const Context = React.createContext('default value')
export default function App(){
   return(
       <Context.Provider value='Seach Movie...'>
            <Header />
       </Context.Provider>
   )
}
function Header(props){
    return(
        <header>
            <Search />
        </header>
    )
}
function Search(props){
    return(
        <nav>
            <Context.Consumer>
                {context => (
                        <input 
                            type='text'
                            value=''
                            placeholder={context}
                        />
                    )
                }
            </Context.Consumer>
        </nav>
     )
}
Enter fullscreen mode Exit fullscreen mode

Context API is the most common solution, but not the only.

Let me know if it helped you or if there's anything missing.

Join me on twitter @akramnarejo I keep sharing tips and resources about javascript, and react.

Discussion (4)

Collapse
xinyan_yu profile image
Chinita Y

Thanks for the information! I would like to ask if the context could survive page refresh? Since in my project I use stores to store all global variables and they will be reset after page refresh.
Thanks in advance :)

Collapse
dawx profile image
Dawx

Context doesn't save data on refresh, to achieve that you can save data to local storage, cookies, or session. If you are using redux for state management, there is redux-persist package that will do the same.

Collapse
akramnarejo profile image
Akram Narejo Author

context doesn't have, what you are asking.

Collapse
lukeshiru profile image
Luke Shiru

Worth mentioning that context also has downsides. Now every time someone uses that Search component, it needs to be wrapped in that context or it will not work as expected. For this scenario is still way better just use props, like this:

export const App = () => (
    <Header searchProps={{ placeholder: "Seach Movie..." }} />
);

export const Header = ({ searchProps, ...props }) => (
    <header {...props}>
        <Search {...searchProps} />
    </header>
);

export const Search = ({ navProps, ...props }) => (
    <nav {...navProps}>
        <input type="text" value="" {...props} />
    </nav>
);
Enter fullscreen mode Exit fullscreen mode

Also, nowadays context is used differently thanks to hooks (you imported it but didn't used it for some reason):

import { useContext } from "react";

export const PlaceholderContext = React.createContext("Default value");

export export const App = () => (
    <PlaceholderContext.Provider value="Seach Movie...">
        <Header />
    </PlaceholderContext.Provider>
);

export const Header = () => (
    <header>
        <Search />
    </header>
);

export const Search = () => {
    const placeholderContext = useContext(PlaceholderContext);

    return (
        <nav>
            <input type="text" value="" placeholder={placeholderContext} />
        </nav>
    );
};
Enter fullscreen mode Exit fullscreen mode

Cheers!