Handling the weird way of Redux State Initialisation

You would have a good feeling about the situation, if you have come to this post after reading Troubleshooting React with Redux & Redux DevTools to which, this article is a sequel. Technically, I encountered the issue after fixing that previous issue! 🤦🏻‍♂️ If you haven't read it, I recommend you to read it and continue this, so that you might enjoy more.

When you are using different components in React JS and you want to have a Global State Management, you might be better off considering a library like Redux and that is what we are using for state management in our enterprise application that I am building now. Obviously, as an over-enthusiastic developer, I didn't read the Redux Docs fully and plunged developing with it.

Most of the developers, now-a-days are like this. They have the confidence that they might be able to figure out sh!t withtout having to read any documentation, but really that is not the case with the current scenario. Even JavaScript is becoming tougher and tougher now-a-days and it is getting extremely complex. But still, I had the guts to take it forward without a protection.

  • Main crux.
  • Used @@INIT
  • Got @@redux/INITb.u.l.l
  • What's the right way.

Problem

At first, it didn't seem like a problem. Things were great and everything was working, until I switched to demonstrate the application to the clients on their environment, which is a Windows Server, contrary to my Apple eco-system. After that the problems started to appear. Instead of an output like the below...

Correct One

In my demo, I was getting something like this...

No text

My boss was constantly telling it is because of the difference in the case sensitivity, and immediately I said that my macOS installation isn't case sensitive. The next thing was imminent that it maybe caused because of not importing the right files, so he said it might be because of the directory separators.

This is a weird one because, in some Linux systems, the directory separator is /, then in some Unix systems (and in some macOS), it is : and while we all know about Windows having the complete opposite of \ as its directory separator.

I was pretty sure that the text wasn't getting translated and it's an issue of translator function not working. Since the translation is manual in our case and the content needs to be given manually by the stake holders, we have a nice JavaScript object for each language or product and it somewhat looks like the below code snippet.

ProductName.js (where the ProductName is either language like en-us or ta-in or a product like Banking)

export default {  
  Edit: "Edit",
  AndSaveReload: "and save to reload",
  LearnReact: "Learn React"
}

Debugging...

I started with looking at the App that has a prop called _, which is the Redux Reducer that contains all the translations. Technically, the above code will be present in the _ and can be accessed like the following.

<p>{this.props._.Edit} <co​de>{_transFileName}</co​de> {this.props._.AndSaveReload}</p>  

I was pretty sure that something is wrong with the Reducer not injecting the right data in it. I started by inspecting the props that is been passed to the <Login> component (that's the main component here) using React Developer Tools. To my surprise, my hunch was right. The _ object was indeed an empty object. I am pretty sure that this is something to do with the Reducer not working as expected.

Empty Object

Now, I go on to find how I get the data into the _ reducer and found this code.

const rootReducer = (state, action) => {  
  if (action.type === "@@INIT") {
    state = {
      _: _("en")
    };
  }
  return allReducers(state, action);
};

I really know this is not the right way to initialise the state, but being a jerk, I thought the default values might not be supported by browsers and tried this approach and this seemed to be a really bad idea. After writing the code, it obviously goes into a transpiler stage, which will convert the JavaScript into IE 8 (or maybe 9) compatible code.

The problem isn't solved yet. I really wanted to know why it worked in macOS but not in Windows. So I kept on trying. I ran the production build in my macOS, thinking it might be a transpilation issue, but alas, the production build version worked on the Windows without any issues. So I thought there should be something else that's making this not work on the source.

I tried debugging the action.type inside the root reducer to make sure that the following code block is even called...

const rootReducer = (state, action) => {  
  console.log(action.type);
  if (action.type === "@@INIT") {
    state = {
      _: _("en")
    };
  }
  return allReducers(state, action);
};

Surprisingly, I found that it was getting called, but the type of the action is what something I was not expecting. As per the documentation, When Redux initializes it dispatches a "dummy" action to fill the state. I thought of checking it as in my macOS machine, it was initialising with @@INIT. To my astonishment, I found that the initial state keeps changing in windows, while it stays the same in macOS! Weird, really weird! 😒

These were the possible action types rendered in Windows:

  • @@redux/INITb.u.l.l
  • @@redux/INITs.h.i.t
  • @@redux/INITc.r.a.p

Solution

After looking into the documentation and how the transpiler works, I was convinced that even default parameters work seamlessly well in so called browsers such as Internet Explorer 8. I used the following one-liner, which is a complicated function with initial parameters defined as a const.

const a = (state = {init: "value"}, action)  
    => (action && action.type) ? action.type : "Hello";

Now, Babel transpiles that into the following extra complex IE 8 compatible sh!t.

"use strict";

var a = function a() {  
  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
    init: "value"
  };
  var action = arguments.length > 1 ? arguments[1] : undefined;
  return action && action.type ? action.type : "Hello";
};

Wow, so I am pretty confident and convinced that the transpiler works to convert the extra super complex, Internet Explorer 8 compatible code. Understanding the whole scenario, I followed whatever the document said and didn't think about anything else, but concentrating on what to get done.

const rootReducer = (  
  state = {
    _: _("en")
  },
  action
) => {
  return allReducers(state, action);
};

After the above update, I was able to see the output of the translation reducer as the data has been injected inside the _ object of the props.

Props

I gave the code inside initial parameters to get the content of en (language, in this case) and woah, it even worked flawlessly in Internet Explorer! Hope this helps someone. Oh yea, I did get the following in my machine and the clients are happy too! 😁

Final



comments powered by Disqus