You Don’t Need React-Redux

Render props are better than the higher-order ‘connect’ function.

There’s a way to use render props with Redux instead of React-Redux’s higher-order component: connect . This can fundamentally change how you think of state in React and Redux much like how the new React Context API works. It has the added benefit of making it easier to use stateless functional components.

I created a ReduxConnection component which handles using render props with Redux. You can always write your own, but this one does it all for you and is mostly a drop-in replacement for connect .

Problems with React and Redux?

One of the biggest issues using Redux in React is the connect higher-order component. I know when I first started using it, it took a while to wrap my head around how it worked and how I was going to use it.

ReduxConnection can be used so long as you understand React; although, if you’re used to React-Redux’s connect , the render props methodology will require a bit of convincing.

Use Render Props with Redux

Here’s an example you’re familiar with using React-Redux’s connect :

And this is how you’d do the same thing with ReduxConnection :

Notice how textSelector is just mapStateToProps but named differently. We can always name those functions whatever we want. The key is you’re selecting something from the state and passing it to children .

The main difference is that higher-order components are outside your component whereas render props are inside. This is where you’ll see the power in ReduxConnection . While it may seems strange at first, if you’re familiar with render props in React-Router v4+, you’ll soon come to realize the power of a dynamic state selector component. With the new Context API, render props are already part of the norm going forward.

The Concept of a Selector

A selector function is a reusable way to:

Select something out of the Redux state.

Have a unified way of doing computation on state before giving it to your component.

Add memorization for performance improvements where needed (see Reselect).

Using selectors, you can pull things from state and pass them into a component using the component prop or render props.

Limit State Updates

ReduxConnection has a way of limiting state updates only when the props coming in are different. This is exactly how connect works, but because you can wrap specific parts of a component in ReduxConnection , you don’t need to be constantly creating separate components where it might not make sense.

The way ReduxConnection is able to accomplish this feat is through shouldComponentUpdate() { return false } . It chooses when to update based on if the props change it skips over the selector so you can put an inline-function without worrying about a bunch of re-renders.

The Future with Render Props

In general, higher-order components tend to have some oddities why using other tooling such as React-Hot-Loader and TypeScript. Although those issues are getting resolved as time goes on with both hacky and legit solutions, it’s clear the industry is moving toward render props.

To find out more about render props, check out the official React page and Michael Jackson’s original post.

In my opinion, higher-order components are cumbersome to write since they require creating extra components where they might not be needed. The last thing I want is to create a bunch of unnecessary indirection.

Take for example trying to wrap a single div in a connect function. That requires pulling it out, creating a new React component, adding PropTypes, and importing that file into your current component. That or finding out a way to have two components in a single file without it becoming unwieldy. ReduxConnection provides a way to do this without the headache of making separate components.

Magic Props

You might want to know where certain props are coming from. When using a higher-order component like connect , that’s all hidden from you. You don’t really have any visibility if that prop is being passed through from the parent component or if it’s directly coming from Redux without having to go into each parent component. I call these “magic props”.

For example:

const propTypes = {

children: PropTypes.node.isRequired,

hasReceivedAuthInfo: PropTypes.bool.isRequired,

isAuthenticated: PropTypes.bool.isRequired,

}

My assumption would be I have to pass in all 3 of those props; although, in reality, 2 of them are coming from connect .

When documenting components, I label which props come in from a higher-order component separately; otherwise, it’s confusing to people consuming your components what that component expects.

Here’s an example of how I compensate for magic props in higher-order components:

const propTypes = {

children: PropTypes.node.isRequired,



// Redux

hasReceivedAuthInfo: PropTypes.bool.isRequired,

isAuthenticated: PropTypes.bool.isRequired,

}

Welcome to extra work for you and your team every time you create new components or add new props or pull new props from state. It’s completely unnecessary maintenance. This kind of thing could be easily missed in a pull request when you’ve got more-important things to look at. I still prefer this method over not labeling where props are coming from, but ideally, we would just use render props.

Render props solves the issue of magic props much like how React-Router v4+ does it .

Take this IsAuthenticated component for example:

With ReduxConnection , it’s easy to see our component takes only children as a prop. I don’t have to account for props outside of my component being passed in such as hasReceivedAuthInfo and isAuthenticated .

This is how it looks with connect :

Simple right? Not really. When you start passing in functions and looking at PropTypes, this become very complex. This is a very small example; although typically, you’ll have larger components with varying state needs. It’s not always that you want to break up these components into smaller components because at some point you’ll run into the problem of indirection.

Here’s another look at both components when you’re using PropTypes:

Because the ReduxConnection example uses composition inside the component, it’s clear where that state is coming from and which props you, as a consumer, need to pass into IsAuthenticated .

If you still think the connect version is better, it gets worse when:

You use mapDispatchToProps .

. You stack higher-order components such as connect and reduxForm .

and . You have to combine two or more state selectors for one component.

You aren’t really aware which components are state-wrapped and which aren’t (think new devs).

Here’s a complex component with magic props in both connect and ReduxConnection :

A major difference in these two examples is the namespace prop. It’s missing when using connect because it’s used under-the-hood in mapStateToProps . You’d have to know to pass it in and to add it to PropTypes because it’s never used by PersonsList directly. When missed, it could quickly turn into a debugging disaster.

Notice as well that there are significantly less PropTypes to keep track of at the component level. Obviously if you’re using Flow or TypeScript, you’ll want to cover the types coming into render props, but from a component props standpoint, this just became a lot cleaner.

Another change from using mapDispatchToProps in connect is we have to define dispatch and pull it in as a render prop. That’s the only way we can push that route. The benefit of ReduxConnection is you can put it anywhere and be very granular about where you’re using the dispatch function.

Refactoring

You might’ve noticed there’s a lot of tabbing in these files. Most people don’t write components as spaced out vertically as I do, but I wanted to make it obvious that render props do, in fact, tab out your components when used inline.

It’s beneficial; although not required in a lot of cases, to pull out some pieces of a component into smaller components. This is where the component prop on ReduxConnection comes in handy. Thanks to React-Router v4+ for the idea!

Now we can slim this down even more:

ReduxConnection allows these sorts of simplifications without having to create a bunch of extra components that themselves have to also be wrapped in connect . PersonsList is now a smart component only telling its children where to get what they need.

Why You Shouldn’t Use mapDispatchToProps

mapDispatchToProps is a fantastic little helper function that removes Redux as a dependency for your component. At that point, it looks like you’re just passing functions as props and then you call those functions as usual.

Sadly, this has the side effect of hiding the reality that you’re dispatching an action when a function is called.

It’s quite possible your component might accept multiple functions and not all of them are wrapped in dispatch. It might also be that you utilize JavaScript scoping and end up not knowing if the function you’re using is the prop passed in or the one being imported. Or in the other case, your higher-order component is passed mapDispatchToProps , but you’re not able to see that when you load up the component and look to either add functionality of fix a bug.

All of these lead to unnecessary confusion when trying to quickly discern the functionality of a component.

Drawbacks of ReduxConnection

There’s something you need know when dealing with render props. If the component providing props (such as ReduxConnection ) customizes shouldComponentUpdate , it will need to be passed the same props used by the render prop function; otherwise, it won’t have the latest props from the parent component.

Here’s an example where I tried to optimize where dispatch is pulled in by wrapping ListItem instead of including it with the parent ReduxConnection :

In this example, ReduxConnection will never update id or name if listItems changes because ReduxConnection has idea you’re closing over id and name . The solution is either to use the simplified example with the component prop pass props in from the map function directly as props on ReduxConnection . This way you can close over them and ReduxConnection will be aware of the closure.

This isn’t a problem with connect because you’re forced to pass props to the component. With connect , there’s no option to close around the props coming in. Thankfully, you can mimic connect 's functionality in ReduxConnection with the component prop and still gain most of the advantages of render props.

While it’s easy to work around this issue, debugging can be a nightmare if you’re unaware of the way it works. In the future this issue will be resolved, but currently, that’s not the case. As long as your team is informed, you should be able to use ReduxConnection and work around the problem with closures.

You could also wrap ReduxConnection with your own component and force it to update with a randomNumber={Math.random()} prop.

Start Using ReduxConnection Today!

You can start using ReduxConnection today! Check it out on npm in its initial incarnation here:

If you’re curious, you can find the source code on GitHub:

https://github.com/Sawtaytoes/Ghadyani-Framework-Redux-Components/blob/master/components/ReduxConnection.js

Special Thanks

My thanks goes out to Jason Nall. His redux-render library inspired me to write my own library. I formatted the basic concepts of ReduxConnection off his original structure.

More Reads

If you’ve got an interest in more topics related to React, you should checkout my other articles: