An experiment to create a zero-dependancies* React app

Issam Zoli
4 min readNov 26, 2018

--

(*) No redux, redux-react, react-router, react-router-dom, react-router-redux, redux-sagas or alternatives

React is the very popular library that makes the UI = f(state) dream a reality. But React is just a UI library, it defines itself as ”a JavaScript library for building user interfaces”. But that leaves a lot to be desired since most real-life apps need routing, state management, server calls and other side-effects management tools. Many libraries offer a whole set of tools to do all that in an opinionated framework, but React doesn’t. It just takes care of your UI and you are free to deal with the rest in any way you see fit. That led to the usual suspects: redux, react-router and redux-sagas or some combination of similar tools.

Since React announced the new context API, people started talking about how Redux is getting obsolete, and now with hooks API everyone is creating his own flavor of Redux and so did I!

To be clear the Redux, React-Router, Redux-sagas combo is very powerful and proven in real-world huge apps, if you are serious about your app the DIY methods aren’t recommended. Furthermore, Redux is not just a state manager, there is a lot of tooling around it which makes it valuable.

This is just an experiment, I didn’t take care of any cleaning or edge cases, it’s basic, straightforward and nothing more.

Redux

With that out of the way, let’s dethrone Redux:

Just like that, that’s the core of a state reducer:

  • Define initial state
  • Provide a way to subscribe/unsubscribe to state changes (As you can see I don’t unsubscribe, I’m a man of my word)
  • Provide a way to dispatch actions to calculate new state and notify subscribers

For convenience we need to provide a way to combine reducers, so we can have multiple reducers with little concerns.

Another annoying thing in Redux is the bootstrap code that you need to add for each action. I tried to simplify that by providing this method:

This provides an object that wraps the action creator and the constant itself, making usage simpler and allows for dynamic creation in case of creating the famous 4 or 5 network request constants Ugh!

Now that we have state manager we need to link it to React:

We need to export a linker between store and children which is the context provider, and then we need a link between that context and components which is the connect HoC.

Now we put everything together:

  • App state is directly connected to the store state
  • When there is a change, App state changes and trigger recalculation of context and sub components.
  • connect accepts a selector to pluck needed values only
  • React.memo is needed to ensure only changed components re-render

Sagas

Redux-sagas is a powerful library, it provides a lot of features to handle multiple asynchronous tasks in many ways similar to streams in Rx. But in many cases it’s used to handles simple asynchronous tasks like network requests. In those cases Promises can go a long way, with some async/await syntax sugar we can achieve similar behavior easily:

As you can see sagas can hook into the state manager as a simple listener that can dispatch.

Router

At first I thought the router is the hardest thing to replace, but a route is a simple component that can calculate whether it should display his children or not based on the url (or current state of history).

  • Router just connects history and store
  • This router in the sense that it’s already bound to the store, unlike React-router which has its own context, then needs another layer to bind it to store.
  • UnconnectedRoute is the one handling everything, it calculate regex based on given path, watches for changes in location to test the regex and push new location state if matched.
  • UnconnectedRoute need to be connected to store in order to have location state

Check the repository for full code.

Conclusion

When I had this working I was impressed by the power of React, thought I was using it for a long time I never DIY such parts. But in the end, in React, if you could turn anything into propagating props, it will automagically work.

Another thing that impressed me are those libraries. Writing something quick, dirty and lightweight like this, makes you think about the features provided and the edge cases those libraries are treating to be much more complex and stable than my hacky code, so be thankful and respectful for such wonderful open-source projects and their authors.

--

--