Prop-drilling helps our Test Driven Development

To build a non-trivial React application, you need to think about state management.

You don’t need to use a third-party library like Redux, though much easier if you do, you could use Context, but you do still need to figure out how to store a global state that can be accessed anywhere in your application.

Prop-drilling or threading is a process of getting data, state or even functions to lower parts of your applications Component tree.

What's not great about prop-drilling

To get a state to the right place, we have to drill (or thread) props through the higher-level components. The top-level, or even mid-level, components themselves may not need those props to function, but we do have to accept and push them because its children do.

The reason that not just the React community, but the larger development community rejects this methodology is that it inevitably leads to a very confusing data model for your application and becomes difficult for anyone to find where data is initialised, where it’s updated, and where it’s used.

After code has been worked on by many developers over many months, things can start to get unwieldy. Over-forwarding props (passing more than necessary, perhaps due to re/moving a component), under-forwarding props, abusing defaultProps can all cause you problems.

What's great about prop-drilling

In its most basic form, it is about explicitly passing values and state throughout the view of your application. This is great because if you were coming to a codebase that uses prop-drilling and decided you want to refactor the state value you would easily be able to track all places it’s used by following the code back up (without having to run it) and make the update.

This can make it clear where data comes from and who can change it.

If we only send required props down this becomes a lot more manageable. For example;

Test driven development is so much simpler

This is where we see the most gain from prop-drilling. Keeping our components agnostic and free from business logic we can stick to our preferred test driven development practice even with our UI components.

Not having to worry about state for every test case means the tests can be smaller, easier to read and more meaningful.

Testing on click or other event based functions is now really simple with a mock function that gets drilled in as a prop. This component does not care what the outcome of a click is as long as the function gets called.

Now we don't have any business logic in our UI component test, that can all be pushed back up to the main component.

Bonus: This type of Test-driven development could also help in making sure elements have IDs (as above), alt tags etc. by baking checks into a test template of UI components. This could even be expanded to include a11y standards in our tests.

How we have been using props-drilling in our applications and testing

We have broken our UI components down to be agnostic and reusable even if they are only required in one place for the time being. This creates very little overhead when developing, but, if left unmaintained, it can cause excess code being pushed into our production build when a component is depreciated. It means we make sure to clean up components no longer being used and follow the props back to make sure they are still required in the parent components.

Each UI component is created using Test Driven Development. We know what it needs to look like when properties change.

Larger components, like a main form wrapper, manage and push props to its children only one to two layers deep. 

A page is then usually made up of only a few of these “larger” components (nav, a form, some content), independent of each other.

The Obligatory TL;DR

  • Prop-drilling might not be as bad as you have read elsewhere.

  • Agnostic components with drilling makes test-driven development super simple and components reusable.

  • Clean up after yourself, if a component is depreciated remove props from the parent where you can.

The views expressed on this blog post are mine alone and do not necessarily reflect the views of my employer, Optus Administration Pty Ltd.

Previous
Previous

Tips on Creating Unit Tests Using Jest

Next
Next

The 3 Musketeers and VS Code Remote Containers