Dissecting the createStore of Redux

Creating a store in Redux is something at the core of the experience of the framework. In most cases, developers use the createStore function to specify the list of reducer and enhancer (middleware). In this article, we will see what is really happening when calling the function.

First of all, it’s important to know that this function can take two or three parameters even if it’s mostly used with two. The first four lines of the function handle the situation. If you pass two parameters the second parameter will be the list of enhancers. If you use three parameters, the third one is the list of enhancers and the second parameter is the default state. In my opinion, this is an error of conception and the second and third parameters should be inverted which would remove the gymnastics required. The next validation is to make sure that the enhancer is a function. I said “list of enhancers” but it takes a function, how so? Has described in the previous article about the dissection of the compose method, Redux work with functions that call functions in a chain. Enhancers work this way as well. So, it means that to pass a collection of enhancer, you will need to compose them. This will give the capability to Redux to call the first method with a parameter and have the information pass through the list.

export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)
  }
  // ... function keeps going but cut for brevity

The function is quite big, therefore I cut it down for the moment. The last line above is invoking recursively the createStore function has a parameter. However, this time the enhancer function is invoked by the enhancer. As we just mention, the enhancer is a function that calls another function and so on to finally come back and actually return the store which is the remaining of the function that we will see soon. However, before moving on the rest of the function, let’s settle few things. The enhancer role is similar to a middleware which is to be a sequence of function to modify a behavior of Redux. However, this one goal is to modify the store. The most popular one is applyMiddleware which we will discuss later. applyMiddleware is a store enhancer. It enhances the store by providing a way to hook middleware between dispatch of action the reducer.

const store = createStore(
  reducer,
  compose(
    applyMiddleware(thunk),
    DevTools.instrument()
  )
)

The code above should be familiar. The first parameter is the reducer and the second one is the store enhancer which contains two stores enhancer: applyMiddleware and Devtool.instrument. Let’s continue the dissection of the createStore function. Before going any further, the code validates that reducer is a function. Once again, reducers are also composable function! Which mean that every reducer will call each of them in sequence. There are some variables that hold all reducers, the list of listeners and the state. The reducers list is required since everytime something will be dispatched, the action must go through the list. The list of listeners is used to inform any changes and the state is the final state at the end of a loop through all the reducers. The getState function lets you have access to Redux state, the subscribe method allows subscription to get notified when changes happen. Most React developer use the React-Redux package that subscribes beneath the scene and it renders the attached React control for you.

  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }

  let currentReducer = reducer
  let currentState = preloadedState
  let currentListeners = []
  let nextListeners = currentListeners
  let isDispatching = false

  function getState() {
    return currentState
  }

 
  function subscribe(listener) {
   // Removed for brevity
  }


  function dispatch(action) {
   // Removed for brevity
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

Finally, the dispatch method calls currentReducer(currentState, action) which is a pointer to the first reducer functions that will call one after the other each composed function with the current state and action. This is why reducers have the signature:

function yourReducer(state = initialState, action) {
  // Reducer logic here
  return state
}

The dispatch method invokes all listener to be notified. That’s it. The last detail around this method is how is constituted a store enhancer. We can deduct from how it’s invoked that the function takes in parameter a single argument which is the createStore function itself which is a function that returns the store object we just analyzed. The enhancer lets you alter everything about the store. In this article, we saw that createStore function lets you create a basic store which is a bare function that accepts subscribers that are triggered when the dispatch method is called. Between the invocation of dispatch and the notification, it calls a reducer function (that can be composed). This is it! In the next article, we will see the store enhancer called “applyMiddleware” which is an enhancer that brings the notion of middleware in Redux.

Dissecting Redux Compose Function

Redux is one of the most popular state management in the JavaScript ecosystem since few months. In this article, we will dissect the method that composes all middleware named “compose”. The role of this method is to aggregate all functions that will have the opportunity to be executed everytime an action is being dispatched. It’s a door open to do something before passing to the next function (middleware). It’s the only opportunity to modify data before reaching the reducers and the store. The method is used once. It is in the popular method applyMiddleware that we will see in a future article. For the moment, just keep in mind that compose function is taking all middleware to place them in a queue where the data will flow sequentially before reaching

Before analyzing the method, let’s look at all of it.

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

That’s it!. And this can be even simpler because the two first ifs are for cases that are rarely used which is composing nothing (no middleware) or composing a single middleware. In the first case, we return a new function that returns the first parameter. For example:

compose()("a", "b", "c") // Return "a"

This example composes nothing. It might seem that we have 3 parameters, but in fact, compose returns a function that has three arguments. When composing middleware, we will place the middleware inside the compose function, not using the middleware as a parameter of the returned function. This is important to understand that the compose function returns a new function and not a value. The condition statement that looks for a length of one simply return the first parameter of the compose function. This is also rarely used as having a single middleware is rare and wouldn’t require using at all the compose function at the first place — you could just use the middleware directly.

Having the two ifs analyzed let’s jump on the last line which is the confusing one. The last line is the line that is mostly to be used because most application using Redux has several middlewares. The first thing to notice is the use of the JavaScript function reduce. The reduce function is applied to an array and call a callback with two parameters which are the accumulated value followed by the value of the array. The callback is executed the same amount of the length of the array. So, if you have 3 middlewares, the reduce function will call three times the callback. Here is a simple example to grasp the concept. The example takes an array and reduces it by summing every number. The callback function is anonymous and will be called 3 times (length-1). The first time the parameter “acc” and “value” will be 0,1; then 1,2; then 3,3. When every element of the array has proceeded, it returns the value which is 6.

console.log([0, 1, 2, 3].reduce(
    function(acc, value){
        return acc + value;
    }
  )
);

The first confusion with the compose function is that the reduce function is returning (…args) which is not clear. It’s a little bit simpler to remove the arrow function to use traditional functions. Here is the same function written with functions.

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce(combineMiddleware)
}

function combineMiddleware(functionWrapper, middlewareToAdd){
  return function(...nextFunction){
    console.log("What is nextFunction:", ...nextFunction);
    return functionWrapper(middlewareToAdd(...nextFunction));
  };
}

The compose function is calling reduce on a named function “combineMiddleware”. At that point, it should be clear that compose method returns a function since the reduce function returns an aggregation of an array and that the array is an array of function hence the result will be a single function. What remains unclear is how we aggregate since we won’t be summing numbers this time.

The combineMiddleware function will return a new function. Since the reduce function takes the return of the callback for the accumulation, this new function will be used on the next invocation. At that point, invoking compose with 3 functions would return a function returned by combineMiddleware. Nothing would happen. Let’s create three fake functions and add some log statements to follow what is really happening.

function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce(combineMiddleware)
}

function combineMiddleware(functionWrapper, middlewareToAdd){
  console.log("Combined!!!", middlewareToAdd);
  return function(...nextFunction){
    console.log("What is nextFunction:", ...nextFunction);
    return functionWrapper(middlewareToAdd(...nextFunction));
  };
}

  const a = function(next){
    console.log("Outside A", next);
    return function(previousReturnedValue) {
      console.log("Inside A", previousReturnedValue);
      return next(previousReturnedValue + 'a');
    };
  };
  const b = function(next){
    console.log("Outside B", next);
    return function(previousReturnedValue) {
      console.log("Inside B", previousReturnedValue);
      return next(previousReturnedValue + 'b');
    };
  };

  const c = function(next){
    console.log("Outside C", next);
    return function(previousReturnedValue) {
      console.log("Inside C", previousReturnedValue);
      return next(previousReturnedValue + 'c');
    };
  };
  const final = function(next){
    console.log("Final", next);
    return next;
  };

 console.log("Compose Output", compose(a, b, c));

We have the same compose, this time with a console.log that will output what is the next function. There are also three functions that return a function. This is how middlewares are constituted and since the compose function takes a function it is compatible. The idea is that each function takes a “next” parameter which is a pointer to the “next middleware” allowing the actual middleware, the inner function to be executed and returning the value transformed to the next one. In this example, we compose A-B-C. The compose will wrap the function to have C wrapping B wrapping A which will start with the value passed down (not provided yet). So, it is actually doing: “return function(A(B(C(“Data here))))”. The console output looks like the following:

Combined!!! ƒ (next){
    console.log("Outside B", next);
    return function(previousReturnedValue) {
      console.log("Inside B", previousReturnedValue);
      return next(previousReturnedValue + 'b');
    };
Combined!!! ƒ (next){
    console.log("Outside C", next);
    return function(previousReturnedValue) {
      console.log("Inside C", previousReturnedValue);
      return next(previousReturnedValue + 'c');
    };
Compose Output ƒ (...nextFunction){
    console.log("What is nextFunction:", ...nextFunction);
    return functionWrapper(middlewareToAdd(...nextFunction));
  }

So, what is “nextFunction” is the final function passed as a parameter to the returned function of “compose”. In Redux, the applyMiddleware function will use it to pass the store.dispatch down (we will see in a future article). As expected, the combineMiddleware method output twice since we have 3 functions. We can see the final output being the function returned by combineMiddleware function. The next function returns the functionWrapper which is the function A, that call the function B with …nextFunction that is function C.

If change the last output statement to have the compose function execute the returned function, we will see more the flow of the execution.

console.log("Compose Output", compose(a, b, c)); // Change this line by:
console.log("Compose Output", compose(a, b, c)(final));

The output is different this time but calls twice “What is next function” since we have 4 functions having the “final” one that will be wrapped also but executed. The major change is that every function gets called.

Combined!!! ƒ (next){
    console.log("Outside B", next);
    return function(previousReturnedValue) {
      console.log("Inside B", previousReturnedValue);
      return next(previousReturnedValue + 'b');
    };
Combined!!! ƒ (next){
    console.log("Outside C", next);
    return function(previousReturnedValue) {
      console.log("Inside C", previousReturnedValue);
      return next(previousReturnedValue + 'c');
    };
What is nextFunction: ƒ (next){
    console.log("Final", next);
    return next;
  }
Outside C ƒ (next){
    console.log("Final", next);
    return next;
  }
What is nextFunction: ƒ (previousReturnedValue) {
      console.log("Inside C", previousReturnedValue);
      return next(previousReturnedValue + 'c');
    }
Outside B ƒ (previousReturnedValue) {
      console.log("Inside C", previousReturnedValue);
      return next(previousReturnedValue + 'c');
    }
Outside A ƒ (previousReturnedValue) {
      console.log("Inside B", previousReturnedValue);
      return next(previousReturnedValue + 'b');
    }

Compose Output ƒ (previousReturnedValue) {
      console.log("Inside A", previousReturnedValue);
      return next(previousReturnedValue + 'a');
    }

The last output is still a function, but this time, not the combine wrapper but the function A. This is interesting since every function was also a function but with a pointer to the next one. It means that that the returned function “A” will be executed and since this one call next (which in that case is “B”) the cascade will continue until the “final” function is called. The final function also calls next and for the moment doesn’t do much. In fact, we can remove the “return next” from function “final” and to have the same output.

Let’s alter another time the last line.

console.log("Compose Output", compose(a, b, c)(final)("!"));

This time, we execute the composition of functions completely. We are passing down the exclamation point. As we saw in the last trace, the “previousReturnedValue” is added before the function, hence we can expect to have the result “!ABC”;

¸
// Same trace until the last output
Inside A !
Inside B !a
Inside C !ab
Final !abc
Compose Output !abc

As we notice, the function A is called first and call the function B and C and final. Removing the “return next” from the final function will print “undefined”.

If we move back to Redux and how it uses the compose function we see that the applyMiddleware use it this way:

dispatch = compose(...chain)(store.dispatch)

This allows having the consumer of a configured Redux to call dispatch(ACTION) and have action passed down. As we can see, the compose takes “chain” which is an array of the middleware configured and pass down as the “final” the “store.dispatch”. It means that the “store.dispatch” will call the result of all the middleware.

In this article, we have dissected the small function “compose” of Redux. We saw that its goal is to wrap multiple functions and weave them together with a callback that allows chaining the result of each of them to finally be able to execute a final function on the cascade of results. For Redux, it will allow developers to dispatch action to reducers and having the dispatched action to alter the flow between the time the action is executed and persisted.

Dissecting the applyMiddleware Function

applyMiddleware is probably the most popular store enhancer[1]. Most people don’t realize that a middleware is a concept built as a store enhancer and in this article, we will see how the concept of middleware leverages Redux’s store enhancer hook on the store to allows creating custom code to be executed between the dispatch of an action and the time the action reaches the reducers.

The applyMiddleware is called when the store is created by the createStore function[2]. The first parameter are the reducers, and the second parameter is the composition of store enhancer. applyMiddleware is most of the time called with the compose function and allows to setup many middlewares. Here is a basic setup with createStore where we can see how the applyMiddleware is invoked.

const store = createStore(
  reducers,
  compose(
    applyMiddleware(middleware1, middleware2, middleware2),
    aSecondStoreEnhancerHere
  )
)

If we recall from the article entitled “dissecting the createstore”[2], the createStore function call at some point the composition of enhancers like the code below this paragraph. For the sake of simplicity, we will assume that we are not composing store enhancer but only have one which will be the applyMiddleware. The only difference with the composition is that the composition would be called one after the other one in sequence. The main idea to grasp at the moment is not the possibility of calling several enhancers one after the other but that the enhancer calls the store and that the return function of the enhancer is called with the reducers and the preloaded state.

return enhancer(createStore)(reducer, preloadedState)

This is crucial to visualize. The enhancer is a function that takes as a parameter the store and outputs a function that will be executed by the createStore with two parameters which is the reducer and preloaded state. This function will return at its turn the store and how to dispatch action to this one.

This is why the applyMiddleware has the following shapes:

export default function applyMiddleware(...middlewares) {
  return (createStore) => (...args) => {

    // Code removed for brevity

    return {
      ...store,
      dispatch
    }
  }
}

If we deconstruct or de-generalize the code of the createstore to be using directly the applyMiddleware‘s store enhancer we would end up with the following code.

return applyMiddleware(createStore)(reducer, preloadedState)

//Or:

const createStoreFromApplyMiddleware = applyMiddleware(createStore);
return createStoreFromApplyMiddleware(reducer, preloadedState);

The applyMiddleware code first task is to call the actual createStore function which returns the store. The second task is to get a reference to the dispatch function. This will be used in the third task which is to create the middlewareAPI object who is sent to every middleware.

const store = createStore(...args)
let dispatch = store.dispatch
let chain = []

const middlewareAPI = {
  getState: store.getState,
  dispatch: (...args) => dispatch(...args)
}
// To be continued, removed for brivety

Since applyMiddleware is having a collection of middleware, the store applyMiddleware store enhancer will call each of them with the middlewareAPI and return all the middleware return values into a chain of result. The chain of results is then composed and invoked with the store’s dispatch which allows every middleware to be executed with a “next” argument that will move the next composed middleware and still have them access the middlewareAPI which contains the dispatch of the store and the current state of the reducer.

chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)

At the end, the whole store enhancer is about 20 lines of code.

export default function applyMiddleware(...middlewares) {
  return (createStore) => (...args) => {
    const store = createStore(...args)
    let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

As we can see, it’s possible to have different behavior like altering the dispatch function in the actual case with the middleware. The function is actually called once at the creation of the store which set up the chain to be called once a dispatch is executed. Since the code is overriding the dispatch and returning a wrapper of composed functions (middleware), every time something is dispatched it will be pass-through all the middleware. The capability to alter dispatch in a store enhancer allows injecting code to be executed after a store[3] is being modified. The code below is an excerpt that illustrates how the compose function could be replaced and used to be returned allowing a hook function.

function dispatch(...args) {
    const dispatchResult = store.dispatch(dispatchArgs);
    hook(notifyListeners, store);
    return dispatchResult;
}

In this article, we have brushed the store enhancer of middleware. In the next article, we will see how middlewares actual work and see in detail how the popular Thunk middleware brings asynchronous capability.

[1]: https://patrickdesjardins.com/blog/dissecting-redux-compose
[2]: https://patrickdesjardins.com/blog/dissecting-the-createstore-of-redux
[3]: https://patrickdesjardins.com/blog/how-to-have-a-hook-before-a-redux-store-notify-its-subscriber-with-typescript

TypeScript with a generic React Component that use generic property

React is fairly straightforward for simple scenario and TypeScript integrates very well with the JSX syntax (called TSX for TypeScript). However, like many systems, when we push on the limit a little, it starts to be less obvious. One case is the one that you want to have a component generic. Imagine that you want to create a reusable component and want to pass a specific format of information by property and regardless of the implementation you just require to have the object pass to have few fields and nothing else. React per se handle this kind of scenario with the flexibility of JavaScript. Although it’s possible with TypeScript, it requires some nimble ability to achieve it.

First of all, let’s settle on a basic generic component and desire property.

interface BaseModel {
    id: number;
}
interface MyTypeThatExtendBaseModelHere extends BaseModel {
}
interface GenericControlHereProps<T extends BaseModel> {
    items: T[];
}
class GenericControlHere<T extends BaseModel> extends React.Component<GenericControlHereProps><T, {}> {
    // ...
}

So far, nothing special else that we are using property that is taking a generic list of item which must have an id field. This is what extend means. Nevertheless, there is a caveat which is generic when it’s time to use the component.

The following code will complain that the property passed is not of the right type. Saying that items are not assignable to type “never[]”.

//...
public render(): JSX.Element {
    return <GenericControlHere items={myList} />;
}
//...

The trick is to create a type of component that will explicitly mention the generic type to use.

type ExplicitUseMyType = new () => GenericControlHere<MyTypeThatExtendBaseModelHere>;
const GenericControlHereWithExplicitDefinedProperty = GenericControlHere as ExplicitUseMyType;
//...
public render(): JSX.Element {
        return <GenericControlHereWithExplicitDefinedProperty items={myList} >
}
//...

This is a lot of gymnastics to satisfy TypeScript. The reason is that when calling directly the generic component that TypeScript cannot infer what will be the type of the property passed in relation to the component. By creating a new type which passes the generic type it fixes the problem. The component knowns that it of a specific type and the property passed is the same in the render, hence everything compiles.

There is a little syntax detail which is that the type created using “new () =>”. This indicates that it’s not an object literal that respect the specific structure, but an instance of the type — it needs to have a parameterless constructor which the React.Component is. The cast is not a pretty strategy but works fine since the type we are casting is having the “new ()” mention. When React will render the casted type, it will be able to invoke the constructor and create the component.

How to get React Router Route Segment

Using React-Router library is almost the defacto in the industry right now. It handles many scenarios around how to route and handle URL on the client side. One specific case is that you may have some custom parameter that you want to extract to show specific information. For example, if you have a user and desire to have an url with the user id to load the user’s profile when the user visits the URL, the routing system must load the user profile component and let you know which user has been requested.

class Page extends React.Component<PageProps, PageState> {
    constructor() {
        super();
    }

    public render(): JSX.Element {
        return <div>
                <Switch>
                    <Route path={"UserProfile/:userId"} component={UserProfile} />
                    <Route path="/" component={MainPage} />
                </Switch>
        </div>;
    }
}
const c = connect(mapStateToProps, mapDispatchToProps)(Page);
export default withRouter(c as any);

The code above illustrates two routes. The first route is the user profile which takes a user id as part of the url. The second is the default page which doesn’t need anything. The challenge is how to get from the UserProfile component the userId. It’s easy once you know what will happen. What happens is that the routing library will push a property to the component specified under match. It means that if you are using Typescript that you must specify that member in the property of the component. Let’s create a simple user profile component that displays the user id.

class UserProfile extends React.Component<UserProfileProps, {}> {

    public render(): JSX.Element {
        return <div>
            <p>
                User Id # {this.props.match.params.userId}
            </p>
        </div>;
    }
}

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

The heart of the problem is to have the match member in your property and to do so you need to add manually a match entry and use the “match” class from the definition file of react-router. This one is generic and let you specify which token in the route you want. In our example, it is the user id.

import { match } from "react-router";
export interface UserProfileRouteTokens {
    userId: number;
}
export interface UserProfileProps {
    match: match<UserProfileRouteTokens>;
}

This doesn’t restrain additional properties, but force you to have one called “match”. Back to the component, you can access the segment of the url with auto-complete. From there, you can load the user data by calling a dispatch action or whatever you want to do in that page.