Component vs Prop drilling in React
Tags: react, redux, javascript
Published: 2019-06-08 15:39:02

---
title: Component vs Prop drilling in React
published: true
tags: react,redux,javascript
canonical_url: https://patrickroza.com/blog/component-vs-prop-drilling-in-react/
series: Of Hooks and Screens
cover_image: https://images.ctfassets.net/0ylo3msmt13u/4NzwDSDlGECGIiokKomsyI/ac152efb96ba171503852edeaba08811/denys-nevozhai-100695-2.jpg?w=1996&h=1496&q=50&fm=webp&bg=rgb%3A000000
description: Recently, often the question is asked if Hooks and Context replaces Redux. It is more a question of do you need Redux, and perhaps how Hooks and Context can help you write cleaner, more functional, more composable code.
---

Recently, often the question is asked if Hooks and Context replaces Redux. It is more a question of do you need Redux, and perhaps how Hooks and Context can help you write cleaner, more functional, more composable code.

{% twitter 1118110824676110336%}

I stumbled upon these topics in:
- https://dev.to/anssamghezala/you-don-t-have-to-use-redux-32a6
- https://dev.to/yakimych/seriously-do-react-hooks-replace-state-containers-3cpl

In these series, I will try to make a point why I think you can achieve most usecases without needing Redux, and perhaps how Hooks and Context may help you with that.

Let's first examine what is often recommended as alternative to Redux:
1. A container component that centralizes the state, and then leverages "prop drilling" to pass props down to all child components. Creating coupling between the components, sometimes multiple levels deep.
2. Multiple components that manage their own state and upgrade to Context/Provider API once state is more shared. Continueing "prop drilling". Also as clients sometimes have a hard time to make up their mind, it may lead to a lot of jumping around of where the state should live.

## Improvement 1: Component Drilling instead of Prop Drilling

A prop drilling sample:
```javascript
const SomeScreen = ({ someAction, someProp, someOtherProp, someOtherChildProp }) => (
  <div>
    <SomeComponent someProp={someProp} />
    <SomeOtherComponent
      someOtherProp={someOtherProp}
      someOtherChildProp={someOtherChildProp}
      action={someAction}
    />
  </div>
)

const SomeOtherComponent = ({action, someOtherProp, someOtherChildProp}) => (
  <div>
    <SomeOtherChildComponent
      prop={someOtherChildProp}
      action={action}
    />
  </div>
)
```
What makes this prop drilling is the fact that `SomeOtherComponent` takes `someOtherChildProp` and `someAction`, which are actually props of the `SomeOtherChildComponent`.

Now with component drilling:
```javascript
const SomeScreen = ({ someAction, someProp, someOtherProp, someOtherChildProp }) => (
  <div>
    <SomeComponent someProp={someProp} />
    <SomeOtherComponent someOtherProp={someOtherProp}>
      <SomeOtherChildComponent
        someProp={someOtherChildProp}
        action={someAction}
      />
    </SomeOtherComponent>
  </div>
)
```
Here we stopped making `SomeOtherComponent` responsible to pass the props for `SomeOtherChildComponent`. Of course this moves the coupling from `SomeOtherComponent` to the Screen instead. Better; it lives closer to the definition, there are less players involved in coupling.

## Improvement 2: State in Hooks/HOCs, so that it can be easily upgraded/downgraded from shared to local state etc.

The goal is to decouple the 'detail' if state is local, shared, or global. Also, the source of the state will be abstracted (imagine that some of the state comes from REST/GraphQL/localStorage it doesn't matter)

```javascript
// written as hooks, but can be written as HOCs as well
const useSomeProp = () => {
  const someProp = // ...
  return { someProp }
}
const useSomeOtherProp = () => {
  const someAction = // ...
  const someOtherProp = // ...
  const someOtherChildProp = // ...
  return { someAction, someOtherProp, someOtherChildProp }
}

const SomeScreen = () => {
  const { someProp } = useSomeProp()
  const { someAction, someOtherProp, someOtherChildProp } = useSomeChildProp()
  return (
    <div>
      <SomeComponent someProp={someProp} />
      <SomeOtherComponent someOtherProp={someOtherProp}>
        <SomeOtherChildComponent
          someProp={someOtherChildProp}
          action={someAction}
        />
      </SomeOtherComponent>
    </div>
  )
}
```
As you can see, the props now come from 2 hooks (which could be written as HOCs as well)

Now imagine that we want to use the same state of `useSomeOtherProp` elsewherec:
```javascript
const SomeContext = createContext()
const useSomeOtherProp = () => {
  const someAction = // ...
  const { someOtherProp, someOtherChildProp } = useContext(SomeContext)
  return { someAction, someOtherProp, someOtherChildProp }
}

// Wrap the `<SomeContext.Provider value={...state} />` around the `SomeScreen`
```

Now imagine that `SomeOtherComponent` has to become more nested, or used in other places:
```javascript
const SomeOtherComponent = () => {
  // moved from SomeComponent
  const { someAction, someOtherProp, someOtherChildProp } = useSomeChildProp()
  return (
    <div>
      <h1>{someOtherProp}</h1>
      <SomeOtherChildComponent
        someProp={someOtherChildProp}
        action={someAction}
      />
    </div>
  )
}

// Move the <SomeContext.Provider where-ever it makes sense to be able to access the shared state.
```

## Slots

Of course component drilling does not mean only `children`, you can also drill components through props ;-)
```javascript
const SomeOtherComponent = ({ children, left, right }) => (
  <div>
    <div>{left}</div>
    <div>{children}</div>
    <div>{right}</div>
  </div>
)

// Usage
<SomeOtherComponent
  left={<SomeChildComponent1 action={someAction} />}
  right={<SomeChildComponent2 ... /> }
>
   Some center content
</SomeOtherComponent>
```

## In closing

There's of course more to it, more trade-offs to consider, room for optimizations etc. But we can address them once they become relevant. That's the beauty of a flexible architecture; make things *just* flexible/plugable enough so that once changed requirements come (and they will), you can respond to them quickly.