A React Pattern to Avoid Apropcalypse

May 11, 2020 | 3 minute read

React patterns are useful to promote code reuse while maintaining component simplicity and flexibility.

Today we’ll go over some React patterns I learned while participating at Byteconf React. React patterns are useful to promote code reuse while maintaining component simplicity and flexibility. This article is a bit on the advanced React side.

Typical Component Development

Lets imagine a custom component that has an accordion UI. So we’ll build this Accordion component.

accordion1

Imagine another developer wants you to allow more flexibility to your accordion so that the order of the accordion items can be customized. Here you might think passing out a props like top so if true then the accordion item becomes the first.

Now, another developer wants you to have the text on the side rather than at the bottom. Then after working on it you change the CSS so it can have it on the side with props as right, then if true it moves to the right.

accordion2

Then things can start becoming complicated when now another use case tell you to implement text on the left. So use cases start to pop up one after the other. Your accordion component starts having a lot of props, that can become hard to control and deal with.

accordion3

Easily you can jump into having a component with record level props (apropcalypse)!

Some problems with a component with lots of props and many use cases to deal with:

  • Hard to maintain
  • Re-renders and JSX that doesn’t even apply to your use case
  • Implementation complexity - breeding ground for bugs
  • API complexity. Harder for other people to use your project. Your documentation can become complex.

So how can we support these use cases without keep adding new props?

Making it Simpler / Flexible

The following implementation might look a bit confusing at the beginning. Note it uses React Hooks, so you might wanna brush up on it before digging into it (you can read my article on Hooks).

patt1

This implementation uses the inversion of control pattern. It has a default reducer, although anyone can use their own version of the reducer.

So with this, we can build our own accordion component that might look like this:

patt2

And then we can pass items to render the accordion in the default way like <Accordion items={accordionItems}>

accordion1

Because component is built on top of a hook then you can modify to make things your way. E.g. lets say we want the accordion to point up now. Then with just a few lines of code differences, the change now becomes the responsibility of who is implementing the code:

patt3

What is important is that this pattern doesn’t add any complexity to the logic behind the component. You can add features to it and have total control of render and no you’re no longer responsible of use cases you don’t want to support.

As all the logic is stored in useAccordion custom hook, it gives flexibility and control as to how a particular user of the component wants the UI to be rendered.

Remember we are inverting control, as it can receive its own custom reducer, props so it can adapt to it. This is a benefit of React Hooks.

Here we are using the systems design principle of composability so that users can use this component and assemble as depending on their needs.

Feel free to watch the Byteconf React presentation Video. The presenter has different examples with reducers to take care of other use cases. Also check the code repo here to play with it yourself!

👋🏼👋🏼🚀