My experience in re-writing a simple library 3 times in 2 years

About four months ago, I posted this to document my ideas at the time to improve my one-and-only React package in a more developer friendly way.

This is a package I created to solve a problem of mine a while ago. Since the initial publish, I re-wrote the package three times. Every time I learned something new, I implemented my knowledge on the package.

First re-writing was after I learned JavaScript classes. So I tried to write the library using pure classes.

Then I learned TypeScript and re-wrote the package again in order to provide TypeScript support. This time I got rid of the class structure and made it more React-y.

Over the time, the users of the package gave some very valuable feedback. Even though I tried my best to respond to everything, there were some design flaws in the package that was bugging me.

So I wrote the post I shared earlier just to document my ideas. And recently got time to implement all of them.

What Changed and How

Global state management feature is removed

React Step Builder used to provide methods for handling form state. If you had an input, checkbox, or select element, you could easily pass the methods provided by the library and it was saving it in a global state. The wrapper component was holding the state pieces from each step in a single location.

Handling state is a very delicate issue for a lot of React developers, including me. People use different solutions which they might not want to give up on.

The questions/concerns I got from developers consolidated the idea so I didn't want to force anyone to use those methods anymore. It was a simple step-by-step interface builder and I wanted to limit it's responsibility to that only.

In the latest version of React Step Builder, global state feature is completely removed from the library. So it's not a library that offers you some methods to handle your form state anymore. Think of it as a library to create any interface where user can go back and forth between different steps. That's it!

Unintuitive Step component is removed

Before, the developer had to create their own Step components in a separate file and pass it as a prop to a special component called Step. This approach has also proved itself to be very cumbersome. I even had trouble using the library in a project at work because of this.

So I researched more about React-y way of dealing with children prop. Using React.Children method, I was able to treat the direct siblings of the main wrapper component as steps.

I came up with this solution solely considering "Composition over Inheritance" principle of React. People should be able to create their component tree as they like and the library should do the rest. I realized I was creating more work for the developers than to save them time.

Now it's up to the developer to create their steps in the same component, or divide them up to separate files. This approach also made it easy for me to decide to halt global state management feature. Because when all the code for each step is in a single place, the state can live in the same place and be served to each step directly or via props, easily.

A Custom Hook created for shared methods

Removing Step component brought about a problem that I really enjoyed solving.

Step component was providing some useful props such as next, prev, jump methods that are used to navigate between steps. Now I had to serve these methods in a different way.

Custom hook solution was my first choice as most React developers are already comfortable with the pattern. So I created a hook called useSteps that provides all the properties and methods that were shared via Step component's props before.

The component that holds the Steps wrapper should be wrapped in StepsProvider component for this to work and at first I didn't really like the idea of forcing the developers to use another wrapper component. However, being free from a special component's props and being able to use those methods anywhere under the provider's tree was the flexibility I wanted. So I went with the StepsProvider solution where the data is shared through React's Context API.

Finally...

I really enjoyed working with this library over the past two years. It's a novice-level piece of software but I learned so much through trying to develop this. It pushed me to research so many different things. Creating software for other developers is also very enlightening in a way that made me feel more responsible for the code I was writing. I kept asking myself, "would I enjoy writing code like this?" It's probably still not perfect, but it came a long way.

Please review the documentation, play with the codesandbox repo, use it in your projects, and let me know what you think!

24