A look at the Redux connect() function

A look at the Redux connect() function

It is no secret that React is one of the most popular libraries for building User Interfaces in today's day and age. I am confident most of you who read this blog have used Redux for managing the overall state of the application in your previous projects.

Ever wondered how the redux connect() function works? Or what are the various JavaScript concepts involved in writing a connect() function?

In that case, I will walk you through the JavaScript concepts involved in writing our own connect() function, which can then be integrated into the Redux library and used in conjunction.

As per the Redux documentation, connect()() function returns

The return of connect() is a wrapper function that takes your component and returns a wrapper component with the additional props it injects. In most cases, the wrapper function will be called right away, without being saved in a temporary variable: export default connect(mapStateToProps, mapDispatchToProps)(Component).

First, let's take a look at Higher Order Functions in JavaScript.

What are Higher Order Functions?

JavaScript treats functions as First Class Citizens, which means that a function can return another function, or a function can be passed as a parameter to other functions or even store function as a value in a variable.

Basically, Higher Order Functions are just functions that return another function or which accept a function as a parameter.

Redux's connect() function is a Higher Order Function that takes two functions as parameters (mapStateToProps and mapDispatchToProps), and it also returns a function that wraps the component.

Now that we have seen the above implementation of Redux's connect() function, we know that connect() is an Higher Order Function. Before writing our own connect() function, we need to learn about closures and currying.

Currying

Currying is a process in functional programming in which we can transform a function with multiple arguments into a sequence of nesting functions. It returns a new function that expects the next argument inline.

Here's an example in JavaScript:

Confused? How does this concept apply to real-world scenarios. Let me give you a scenario.

*In our application, there is a case where the result of some calculations has to be doubled. We typically did this by passing the result with 2 as arguments to the multiply function in the following way: multiply(result, 2);

A function can be returned from currying, so it can be stored and used with other sets of parameters if needed.*

Hopefully, you got the idea of how redux implements the connect()() function, using currying.

export default connect(mapStateToProps, mapDispatchToProps)(OurComponent);

Closures

Closures simply refer to the scope of the outer function being accessible by the inner function, even after the outer function has been executed and removed from the call stack.

Lets suppose we have an outer function A and inner function B.

*From the concept of Higher Order Functions, Currying, we learned that the connect()() function is a HOF (Higher Order Function) that takes two functions as parameters and returns an anonymous function, which we use to wrap our component, by calling it using Currying.

Hence connect() is an outer function, whereas anonymous function returned is an inner function, so the props passed to connect() can be accessed by anonymous inner function, even after connect() has completed its execution using closures.

Now that all of these are in place, let's move on to writing our own connect() function*

Let's write our own connect() function

We are going to use a starter application counter, which has increment/decrement actions connecting to a redux store. So the plan is to write our own connect function first, and then integrate the working application with it.

The GitHub link of the counter application is as follows:

Github - own_connect_fn_starter

ss1.JPG

A simple counter application where the counter value is stored at redux store, which can be incremented or decremented by dispatching a redux action and updating the reducer. The Counter component is connected to redux store using react-redux connect() function.

Our understanding is that connect() is an HOF (Higher Order Function) that takes two functions as arguments and returns an anonymous function. Let's build on this idea.

Now, with the Anonymous Function receiving our component as an argument, we can pass it through with Currying. Next, we'll create our anonymous class component within the Anonymous Function, and the class will be returned by the Anonymous Function.

Here, we are using anonymous class to return our WrappedComponent inside of an anonymous function based on the HOF pattern.

We can now pass the component props along with the props generated by mapStateToProps and mapDispatchToProps. The implementation states that mapStateToProps requires an overall redux state and component props as parameters, while mapDispatchToProps requires a dispatch function and component props as parameters.

The component props can be accessed with this.props, but how do we get the state and dispatch method of the redux store?

In the process of integrating redux into our application, a store will be created. We will export that store and import it in our connectFn file. We can access them using that store object.

There's still work to do. At this point, you may observe component is rendered on screen without any errors, however when clicking on increment/decrement the value of counter does not update. It is because we have to re-render a component whenever its state changes.

We can do this by subscribing to the store and rendering it whenever state change happens.

We can import the connectFn and can be used as follows:

export default connectFn(mapStateToProps, mapDispatchToProps)(Counter);

That's it!!! We built our own connect() function and integrated it with the Redux store.

Final code in the Github repo

Hope it's useful

A ❤️ would be Awesome 😊

HappyCoding