3 Ways to Avoid Prop Drilling in Vue/React

Learn three effective methods to avoid prop drilling in Vue and React, ensuring cleaner and more maintainable component-based development.


How to Avoid Prop Drilling in React

In order to write scalable, reusable, and maintainable applications with React, you'll need to go beyond the surface of using React components, useEffect, useContext, useState, and the like. It involves learning in detail how React works in more depth.

And if you don't properly understand these key React concepts, you can run into various issues, like prop drilling.

In this tutorial,  you'll learn what prop drilling is. I'll also teach you how to intuitively avoid it without relying on React context. In the end, you'll understand how to identify prop drilling without thinking and fix it with precision.

 

What is Prop Drilling?

Prop drilling occurs when a parent component generates its state and passes it down as props to its children components that do not consume the props – instead, they only pass it down to another component that finally consumes it.

Below is an example of prop drilling in React:

function App() {
  const [profile, setProfile] = useState({ame: 'John'}); 
  return ( 
    <div> <Header profile={profile} /> 
    </div> 
  ); 
} 
  
function Header({ profile }) { 
  return ( 
    <header> 
      <h1>This is the header</h1> 
      <Content profile={profile} /> 
    </header> 
  ); 
} 

function Content({ profile }) { 
  return ( 
    <main> 
      <h2>Content Component</h2> 
      <p>{profile.name}</p> 
    </main> 
  ); 
} 

export default App;

If you check out the example above, you'll notice that profile is passed from the App component through the Header to the Content component, which eventually makes use of the props. This is commonly referred to as prop drilling as the Header component doesn't consume the prop but only passes it down to the Content component that finally consumes it.

Now that you understand what prop drilling is, the next challenge is to figure out how to avoid it because it's not always an intuitive process.

You'll need to start exploring methods to address it. While you can use component composition and React context to resolve it, the challenge lies in not always recognizing the issue until later.

To truly master the art of handling prop drilling intuitively, you must learn how to identify elongated props and contexts.

What is an Elongated Prop?

Where is the love sung by The Black Eye Peas recreated in a tunnel underpass.

An elongated prop is a prop that is not consumed but it is only passed down to another component. When a component receives a prop from its parent and doesn't consume the prop, it passes the prop down to another component. This prop is called elongated prop because it has been extended.

Whenever you see a prop being passed down by components that neither creates nor consumes the prop, you have an an elongated prop (as well as prop drilling) in your code. The code snippet below is an example:

function Profile({ user }) { 
  return ( 
    <header> 
      <h1>This is the header</h1> 
      <Content user={user} /> 
    </header> 
  ); 
}

user, in this example, is an elongated prop as it is neither created nor consumed by the Profile component. Instead, it is only passed down to the Content component. And that means we have extended user through a component that doesn't need it so that it can get to the one that does.

Now, let's revisit the example we used to illustrate prop drilling. Wait, are you thinking what I'm thinking? The prop that's being passed down in the prop drilling example is indeed an elongated prop, right? Yes, you've got it.

function App() {
  const [profile, setProfile] = useState({ame: 'John'}); 
  return ( 
    <div> 
      <Header profile={profile} /> 
    </div> 
  ); 
} 
  
function Header({ profile }) { 
  return ( 
    <header> 
      <h1>This is the header</h1> 
      <Content profile={profile} /> 
    </header> 
  ); 
} 

function Content({ profile }) { 
  return ( 
    <main> 
      <h2>Content Component</h2> 
      <p>{profile.name}</p> 
    </main> 
  ); 
} 

export default App;

In the code above, you can observe that the prop passed to Header is created in the App component. Then, Header passes it down to its child component named Content. As a result, the profile being passed down can be considered elongated because it is passed through a component (Header) that neither creates nor consumes it down to the one that does.

The Header component passing down the prop it doesn't create or need is unnecessarily stretching the context of the prop.

Now, the question is, how do elongated props help to intuitively avoid prop drilling in React? They make it easy for you to spot props being used where they're are neither created nor consumed.

Rather than focusing on how to solve prop drilling, elongated props enable you to avoid it. This is because it's intuitive to recognize when a component neither creates nor consumes props, and that helps you to know the component is irrelevant.

But before you learn how to quickly avoid prop drilling with your understanding of elongated props, it is important that you know the main causes of prop drilling. Then you'll truly know how to avoid it without thinking about it.

What Causes Prop Drilling?

»What is your story?«

Prop drilling doesn't occur out of thin air. It's a consequence of inadequate component organization, and it is not a React problem. It is a thinking or design problem.

You won't encounter an instance of prop drilling without observing one of the following layout mistakes:

First of all, grouping static elements and dependent components together to achieve an appealing UI design is the major cause of prop drilling. You can't avoid prop drilling when your UI groups static elements and dependent components together in a parent. The parent component clearly won't use the prop, as everything within it is a static element – except the component that needs a prop.

Here's an example:

function Header({ profile }) { 
  return ( 
    <header> 
      <h1>This is the header</h1> 
      <Content profile={profile} /> 
    </header> 
  ); 
}

In this case, static elements <header> and <h1> are grouped with a dependent component Content – and that's why we have prop drilling therein.

Provided that the Content component is independent or takes no props, it won't need profile and there won't be prop drilling in the first place. This is why forcing a component that should be independent to take props from its parent is a recipe for prop drilling in React.

Second of all, when a component accepts props that it doesn't use but merely passes it down to its children, this is a sign that you have prop drilling in your component:

function App () { 
  const [profile, setProfile] = useState({name: "Ayobami"})
  return ( 
    <>
      <Parent profile={profile} /> 
    </>
 ); 
}; 

function Parent({ profile }) { 
  return ( 
    <div>
      <Hero profile={profile} /> 
      <Features profile={profile} /> 
    </div>
 ); 
}; 

In this case there is prop drilling because the Parent component takes profile and it doesn't use it though it passes it down to its children.

Third, when a component that represents an independent section of a page is forced to take props from its parent, prop drilling is inevitable. It should ideally be self-contained with its state and operations.

The exception would be if it's intentionally tied to its parent for specific reasons. In such cases, prop drilling becomes a necessary trade-off.  

If you revisit the example of prop drilling cited in this article, you will realize it has a prop drilling issue because the Content component which could have been an independent component by having a state is forced to receive props from its parent.

And finally, the presence of elongated props is a sure sign of prop drilling. Since an elongated prop is a fundamental element that's consistently present in every case of prop drilling, grasping this concept allows you to instinctively avoid prop drilling.

When you spot an elongated prop, you can be certain that one of the other three mistakes is also in play. In short, an elongated prop is a prop that is not consumed and is also passed down to another component.

So grouping static elements with dependent components, forcing components to take props, elongated props, and receiving a prop without consuming it are the signs to recognize prop drilling in React.

How to Fix Prop Drilling with Component Composition

Component composition is a good approach to fix prop drilling. If you ever find yourself in a situation where a component passes down a prop it neither creates nor consumes, you can use component composition to fix it.

But to use component composition, you need to understand a component context.

What is a component context?                           ‌

The context of a component encompasses everything that is visible within it, including state, props, and children. The following code further illustrates this concept:

function App() { 
  const [profile, setProfile] = useState({name: 'Ayobami'}); 
  return ( 
    <div> 
      <Header profile={profile} /> 
    </div> 
  ); 
} 

export default App;

In this scenario, the context of App refers to everything we can see within the App component – including the profile prop, the Header, and other App content. Therefore, any data created in the App component should ideally be utilized within the App component itself, either as its own data or as props to its children.

Prop drilling always emerges when the children receiving the props doesn't consume it but only passes it down to its children.  

To avoid prop drilling in this case, any grandchildren components that require access to the same props, especially when their parent don't consume the data, should be passed as children ensuring that the data remains within the App context.

export function App() { 
  const [profile, setProfile] = useState({name: 'Ayobami'}); 
  return ( 
    <div> 
      <Header> 
        <Content profile={profile} /> 
      </Header> 
    </div> 
  ); 
}

Or

export function App() { 
  const [profile, setProfile] = useState({name: 'Ayobami'}); 
  return ( 
    <div> 
      <Header children={<Content profile={profile} />} > 
    </div> 
  ); 
}

As you can see, we have resolved the prop drilling issue in the previous example, even though we still have a redundant component, <Header>, right? We've successfully addressed prop drilling through component composition.

This process is quite straightforward because we concentrate on recognizing elongated props and repositioning them within appropriate contexts.

The concept of prop drilling is problem-focused, but prop elongation is solution-driven. When dealing with elongated props, our primary goal is to identify props that are not consumed but only passed down to another components.

How to Fix Prop Drilling by Moving State to the Consumer

Prop drilling can also be fixed by moving state to where it is consumed. The example of prop drilling in this article has a component named Content. But the component is forced to receive a prop from its parent instead of having a state and be an independent component – and so we have prop drilling.

We can fix the prop drilling in this case by moving the profile state to where it is consumed.

Let's revisit the example:

function App() {
  const [profile, setProfile] = useState({ame: 'John'}); 
  return ( 
    <div> 
      <Header profile={profile} />
      <Footer profile={profile />
    </div> 
  ); 
} 
  
function Header({ profile }) { 
  return ( 
    <header> 
      <h1>This is the header</h1> 
      <Content profile={profile} /> 
    </header> 
  ); 
} 

function Content({ profile }) { 
  return ( 
    <main> 
      <h2>Content Component</h2> 
      <p>{profile.name}</p> 
    </main> 
  ); 
} 

export default App;

We can fix prop drilling in this case by moving profile to where it is consumed:

function App() { 
  return ( 
    <div> 
      <Header />
      <Footer profile={profile />
    </div> 
  ); 
} 
  
function Header() { 
  return ( 
    <header> 
      <h1>This is the header</h1> 
      <Content /> 
    </header> 
  ); 
} 

function Content({ profile }) { 
  const [profile, setProfile] = useState({ame: 'John'});
  return ( 
    <main> 
      <h2>Content Component</h2> 
      <p>{profile.name}</p> 
    </main> 
  ); 
}

Now that we have lifted the profile to the Content component where it is consumed, the App component doesn't have a state, while the Header component doesn't receive a prop again as the Content component has its state.

But wait! There is a problem. The Footer component needs the state we moved away from App. There you are! That is the problem with lifting or moving state to where we think it is needed. In this case, if the Footer component doesn't need it, we won't have any issue – but Footer also needs the prop.

Now that Footer needs profile as a prop, we need to solve prop drilling with another method.

How to Fix Prop Drilling with a Children-Replacing-Parent Strategy

Earlier in this article, we talked about how to use component composition and moving state to its consumer to solve prop drilling. But as you saw, they have some issues – duplicated components or states.

But using this children-replacing-parent approach fixes the problem effectively:

Working but could be better:

export function App() { 
  const [profile, setProfile] = useState({name: 'Ayobami'}); 
  return ( 
    <div> 
      <Header> 
        <Content profile={profile} /> 
      </Header> 
    </div> 
  ); 
}

function Header({ profile }) { 
  return ( 
    <header> 
      <h1>This is the header</h1> 
      <Content profile={profile} /> 
    </header> 
  ); 
}

The example above shows a solution to the prop drilling example in this article. But as you can see, it has a redundant component, as Header does nothing.

Here's a better version:

export function App() { 
  const [profile, setProfile] = useState({name: 'Ayobami'}); 
  return ( 
    <header> 
      <h1>This is the header</h1> 
      <Content profile={profile} /> 
    </header> 
  ); 
}

In the above code, we enhance the component composition solution we previously implemented for the prop drilling example by replacing the redundant Header component with its content in its parent (App).

What to Avoid

photo-1587065915399-8f8c714ab540?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDEwfHxkYW5nZXJ8ZW58MHx8fHwxNjk5MzIzMDgxfDA&ixlib=rb-4.0

It's essential to highlight what to avoid when dealing with prop drilling to prevent unnecessary challenges.

  • Avoid React Context, if possible, to fix prop drilling. This approach ties your component to a specific context, restricting its usability outside of that context and hindering composition and reusability.
  • Steer clear of redundant components by employing a children-parent replacement approach. This approach naturally incorporates component composition without introducing redundant components or states when resolving prop drilling.

By avoiding elongated props, you pave the way for crafting maintainable, high-performing, reusable, and scalable React components. It simplifies the process of lifting states and components by removing the struggle of deciding where to place them.

With your understanding of elongated props, you can confidently position props and components within the right context without undue stress.

In short, you can now discover prop drilling intuitively by paying attention to any component that takes props it doesn't consume and only passes it down to another component.

Thanks for reading – cheers!


How to Avoid Prop Drilling in Vue

Eliminate prop drilling in Vue: Implement Vuex/Pinia, scoped slots, component composition, provide/inject, and event bus to improve app performance

Prop drilling is an annoying thing that happens a lot when you're working with Vue.js.

It's when you have to pass a prop through a bunch of components just to get to some data that was set up way higher in the component tree. This can make your code a total mess and slow down your Vue components.

In this article, we're gonna dig deep into prop drilling, look at why it's a pain, and how it can mess up your code.

We'll also talk about some cool tips and tricks to help you avoid prop drilling, making your Vue.js apps easier to work on, faster, and able to grow.

By learning about the downsides of prop drilling and using the ideas in this article, you'll be able to build better and more organized Vue.js apps.

Key Takeaways

Prop drilling can create messy code and slow down Vue.js apps

Avoiding prop drilling improves code readability, manageability, and performance

Use techniques like global state management, slots, component composition and provide/inject to prevent prop drilling

What is Props Drilling?

Prop drilling, or "prop threading" as some people call it, happens in Vue.js apps when data has gotta go through a bunch of component layers to get where it's needed.

Imagine a top-level component with some data that a deep-down component needs.

To make that happen, the data's gotta be passed down as props through all the components in between, even if they don't need the data themselves. This whole passing down thing can make your code super hard to maintain, understand, and manage.

Plus, it can create a crazy web of dependencies, making it tough to find where problems come from or to clean up your code.

Why Should You Avoid Prop Drilling in Vue.js?

Ditching prop drilling is a must for a few reasons:

Keep your code neat: Prop drilling can mess up your code, making it a pain to add new stuff or fix bugs since it's hard to keep track of data dependencies.

Easy on the eyes: Code with lots of prop drilling can be a headache to read and debug, slowing you down and making it tough to understand what's going on.

Room to grow: When your app gets bigger, prop drilling can make managing state and data flow a nightmare, holding back your project's growth and making changes harder.

Smoother debugging: Steering clear of prop drilling makes your app's data flow simpler, so it's easier to spot and fix issues, cutting down on your code's overall complexity.

Does Prop Drilling Affect the Performance of Your Vue.js App?

When you're working on Vue.js apps, you gotta think about how different coding habits can impact performance.

Prop drilling is one of those things that can mess up your app's speed if you don't handle it right.

Prop drilling can mess with your Vue.js app in a few ways:

Too many re-renders

When you pass props through a bunch of component layers, each one might re-render when the prop value changes, even if it doesn't use the prop.

This can create a domino effect, making a bunch of components re-render and use up more resources, which slows down your app.

More complexity

Prop drilling can make your app's data flow super confusing and tough to manage. This means you're more likely to run into bugs and performance problems.

Harder to optimize

When data goes through a bunch of components, it's tricky to figure out which ones are causing performance issues and fix them.

Prop Drilling Example in Vue

Consider a scenario where we have three nested components:

Parent

Child

GrandChild

We want to pass a piece of data, let's call it message, from Parent to GrandChild.

Here's how the components might look:

// ParentComponent
<template>
  <div>
    <ChildComponent :message="message" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: "Hello from Parent Component",
    };
  },
};
</script>
// ChildComponent
<template>
  <div>
    <GrandChildComponent :message="message" />
  </div>
</template>

<script>
export default {
  props: {
    message: String,
  },
};
</script>
// GrandChildComponent
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: {
    message: String,
  },
};
</script>

In this example, the message prop is passed from Parent to Child, and then from Child to Grandchild.

So, this way works, but it gets kinda annoying when your component tree gets more complicated.

Just think if you had a bunch of components between Parent and GrandChild - you'd have to pass the message prop through all of them.

How to Avoid Prop Drilling?

Here's how you can dodge that annoying prop drilling in your Vue app.

Global State Management

Check out Vuex/Pinia, they're like the cool kids on the block for state management in Vue. They let you share data across components without prop drilling, acting like a central hub for your app's data. Super handy!

Pass Props Only When Needed

Just pass data through props when a component needs it. Don't bother with those middleman components that don't use or change the data.

Slots

Scoped slots in Vue let you pass data straight from parent to child components, with no props needed. It's a great way to ditch prop drilling in some cases.

Component Composition

Break your UI into smaller, reusable bits. This way, you can keep data and functions in specific components, so you don't need prop drilling as much.

Using Provide and Inject

Provide and Inject is like this cool trick that lets you send data to your child components without using props. You just give the data in the parent component and then, boom, inject it into the child component.

No props needed, easy peasy!

Event bus

An event bus is like a walkie-talkie system for your components that aren't directly related. It's a global chat channel that lets components talk without using props or parent-child relationships.

Even though the event bus seems cool at first, it's better to use stuff like provide/inject or global state management. They're just more solid and easier to maintain when it comes to component communication.

Conclusion

In this article, we looked at prop drilling, a usual problem in Vue.js apps that can cause untidy code and slow speed.

We talked about what it is, why it's an issue, and how it can impact your app's speed.

We also gave examples and offered some helpful hints to prevent prop drilling, like using global state management, giving props only when required, using slots, component composition, and provide/inject.

By knowing and handling prop drilling, you can create improved and more orderly Vue.js apps.

#react #reactjs #vue #vuejs #javascript

 

3 Ways to Avoid Prop Drilling in Vue/React
17.25 GEEK