How to avoid React prop drilling
I believe that, like me, most React developers have encountered the problem of prop drilling during their careers.
Usually, this is not the most severe problem, but it clutters the code, makes it difficult to maintain and read, and most importantly — reduces efficiency. Recently I discovered a very elegant solution that made me think, “How did I not know this before?” so I’ve chosen to share it with you.
The famous problem
Prop drilling refers to repeatedly transferring data from a parent component to nested child components in order for those child components to use or share data.
The problems with prop drilling are:
- Bad and unreadable code style.
- Components are used as an information transfer pipe.
- Difficulty in maintaining the code.
- Inefficiency (rendering components unnecessarily).
Take a look at the example in the following schema (drilled props colored in red):
The journey toward the solution
A brief intro to the system
Our system displays a video player of a surgical operation. Next to it, there is a timeline of the stages of the operation and additional insights. Below the video player are tabs containing general information about the operation.
Each part — the video, the timeline, and the tabs below — stands on its own as a component with many children components.
Introduction to my feature
Here is the feature I was working on, and how prop drilling became a big problem.
I needed to create a gallery of screenshots that were taken by a surgeon during an operation. I decided to place it as a new tab under the video player.
The snapshots needed to be shown in the timeline at the moment they were taken. When clicking on a snapshot image (from a gallery or timeline), the image should have increased to a slider display above the whole screen (like a modal).
In terms of functionality, it should have supported renaming and downloading the images from any of the indicated sections.
My implementation at that stage was to insert the data of the snapshots into an existing OperationContext and drill the functions through props from the parent component to the children components (timeline, gallery, slider).
I had a gut feeling that the code was cumbersome, but the approach was to release an initial version as soon as possible.
Possible but less preferable solutions
Along the way I tried to solve the problem using Context, a common solution to the prop drilling problem. In my opinion, it didn’t simplify the code and even complicated it. Other than that, there were relatively few functions and states and it felt like killing an ant with an elephant.
Another solution is Components Composition, which I prefer less because it makes the code more difficult to read and maintain.
The straw that broke the camel’s back: After the release of the initial version, there was a demand to add additional functions and states that should drill along the way.
During a joint thought session with a senior team member, he taught me the following method.
The solution — customized hook
Creating our own hook: use Snapshots
In the following section, I’ll explain how I used the customized hook, and show you how to do it step by step. Before you start, I recommend maintaining the data in a context (assuming it is shared from several places), in order to have one source of truth.
Step 1: Create a file that includes all relevant functions, states, and data processing.
Step 2: Import and Initialize the hook from the required parts of the application.
Pay attention to the fact that you need to pass props during initialization if you require them in your hook definition.
Step 3: Use it as needed inside each component.
You can choose which part to use from the hook (here I selected snapshotItems only).
How does this solve the problem?
A. The code is readable and clean — no prop drilling!
We can add the ‘useSnapshots’ hook only in relevant components.
B. Components are not used as an information transfer pipe anymore.
C. Maintaining the code may be done only in the hook file, so it’s easier.
D. Components are not rendered unnecessarily since the props are not passed through them.
I like this concept and have been using it quite a lot. What do you think? I would love to hear more solutions, improvements, or other uses in creating your own hook 🙂