DEV Community

abhmohan
abhmohan

Posted on

Props drilling and context api

Hello Guys,

In this article we will see what is props drilling and how we can use context api to avoid it.

Props drilling happens when we pass props to the destination components through the intermediate components. These intermediate components just forward the props deep down the component tree without actually using them.

Let's understand with the help of an example.

function App() {
  const [searchText, setSearchText] = useState('');

  const handleChange = (e) => {
    setSearchText(e.target.value);
  }

  return (
    <div className="App">
      <input onChange={handleChange} value={searchText}/>
      <List searchText={searchText} />
    </div>
  )
}

const List = ({searchText }) => {
// This component just forwards the searchText to the ListItems component
  return <ListItems searchText={searchText} />
}

const ListItems = ({ searchText }) => {
  const filteredName = names.filter(name => name.includes(searchText));

  return (
    <ul>
      {filteredName.map(name => <li>{name}</li>)}
    </ul>
  )
}


Enter fullscreen mode Exit fullscreen mode

Here we have searchText which is passed to the List component and the List component forwards the searchText to the ListItems component. This is what we call props drilling.

Even though the List component doesnot use the searchText and just forwards it to the ListItems component, it still rerenders and that is unnecessary.

With context api, we donot have to pass the props to the intermediate components and the components that are wrapped inside the context provider can use the props directly inside them. Let's see how we can achieve this.

export const AppContext = createContext({})

function App() {
  const [searchText, setSearchText] = useState('');

  const handleChange = (e) => {
    setSearchText(e.target.value);
  }

  return (
    <AppContext.Provider value={{ searchText }}>
      <div className="App">
        <input onChange={handleChange} value={searchText}/>
        <List /> // we didn't pass the search text
      </div>
    </AppContext.Provider>
  )
}

const List = () => {
  return <ListItems /> // we didn't pass the searchText
}

const ListItems = () => {
  const { searchText } = useContext(AppContext);
  const filteredName = names.filter(name => name.includes(searchText));

  return (
    <ul>
      {filteredName.map(name => <li>{name}</li>)}
    </ul>
  )
}
Enter fullscreen mode Exit fullscreen mode

As you can see from the above code, we created App context(AppContext) using createContext and wrapped everything inside App component with AppContext.Provider and passed a value(whatever data that needs to be sent to the child components) prop. Inside ListItem component, we used useContext hook and passed the AppContext to it and extracted the searchText. It is interesting to notice that we didn't pass the searchText to the List and ListItems components.

That's all for this article.
Thank you.

Top comments (0)