DEV Community

Cover image for Props Drilling and understanding React Context via them
sushmeet sunger
sushmeet sunger

Posted on • Updated on

Props Drilling and understanding React Context via them

Introduction

If you pass props around to multiple components, where in some cases, the elements receiving them are not even using them, then you are prop drilling. It's like if you have 3 components A, B and C and you pass prop name from component <A name="Tony" /> to component <B />. But component B doesn't even use the name prop. It simply passes it on to component C where the prop is actually used.

Context API provided a mechanism to pass data through the component tree, without having the need to pass props manually down every level.

Let's begin with an example

import { useState } from "react";

const App = () => {
  const [input, setInput] = useState("");
  const inputHandler = (e) => setInput(e.target.value);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <label>Input </label>
      <input value={input} onChange={inputHandler} />
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Image description

Here we have a simple input box, where you can enter some text.

Let's refactor this component so that the state and the onChange handler are passed from the App component to another component called InputStuff.

import { useState } from "react";

const InputStuff = ({ input, inputHandler }) => {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <label>Input </label>
      <input value={input} onChange={inputHandler} />
    </div>
  );
};

const App = () => {
  const [input, setInput] = useState("");
  const inputHandler = (e) => setInput(e.target.value);

  return <InputStuff input={input} inputHandler={inputHandler} />;
};
Enter fullscreen mode Exit fullscreen mode

The InputStuff needs a reference to the input and inputHandler state, so we're sending some props there. Let's refactor it once more to add another layer in our component tree.

import { useState } from "react";

const InputLabel = () => {
  return <label>Input </label>;
};

const InputDisplay = ({ input, inputHandler }) => {
  return <input value={input} onChange={inputHandler} />;
};

const InputStuff = ({ input, inputHandler }) => {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <InputLabel />
      <InputDisplay input={input} inputHandler={inputHandler} />
    </div>
  );
};

const App = () => {
  const [input, setInput] = useState("");
  const inputHandler = (e) => setInput(e.target.value);

  return <InputStuff input={input} inputHandler={inputHandler} />;
};

Enter fullscreen mode Exit fullscreen mode

CodeSandbox URL showing the above code here

Voila this is prop drilling. To get the input state and inputHandler handler to the right places, we have to drill props through the InputStuff component. The InputStuff component itself doesn't actually need those props to function, but we have to still accept them and forward those props because its children need them.

Props drilling has both pros and cons. In a contrived example like this we do not have much issues, but once you have deeper layers and need some props everywhere, we can take advantage of the React Context API.

Here is the above example using React Context API

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

const InputContext = createContext();

const InputLabel = () => {
  return <label>Input </label>;
};

const InputDisplay = () => {
  const { input, inputHandler } = useContext(InputContext);
  return <input value={input} onChange={inputHandler} />;
};

const InputStuff = ({ input, inputHandler }) => {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <InputLabel />
      <InputDisplay input={input} inputHandler={inputHandler} />
    </div>
  );
};

const App = () => {
  const [input, setInput] = useState("");
  const inputHandler = (e) => setInput(e.target.value);

  return (
    <InputContext.Provider value={{ input, inputHandler }}>
      <InputStuff input={input} inputHandler={inputHandler} />
    </InputContext.Provider>
  );
};

Enter fullscreen mode Exit fullscreen mode

Here is the codesandbox ex using Context API here

Conclusion

  • We understood props drilling and what the Context API are.
  • Props Drilling by itself is fine and is useful to trace the path of how data flows, and hence eventually make refactoring and changes easy although this can spiral out of hand quite easily
  • Context API can be used to share data that is considered global for React Components. It provides a mechanism to have props available at any level, without explicitly passing the props. It is ideally used for passing Theme, Locale to many components in an application.

Top comments (0)