Why Redux Use Pure Function

Before going straight to the question, let us steal a piece of code from Redux that features combineReducers() function.

It seems that my previous understanding on how Redux implements combineReducers() does not aligns with the current implementation.

Here's my prior understanding on how it works:

const combineReducers = (reducers) => {  
  return (state = {}, action) => {
    return Object.keys(reducers).reduce(
     (nextState, key) => {
       nextState[key] = reducers[key](
         state[key],
         action,
       );
       return nextState;
     },
     {});
  }
}

Current Implementation:

var reducerKeys = Object.keys(reducers);  
var finalReducers = {};  
for (var i = 0; i < reducerKeys.length; i++) {  
  var key = reducerKeys[i];
  finalReducers[key] = reducers[key];
}
var finalReducerKeys = Object.keys(finalReducers);

return function combination() {  
    var state = arguments[0];
    var action = arguments[1];

    var hasChanged = false;
    var nextState = {};
    for (var i = 0; i < finalReducerKeys.length; i++) {
      var key = finalReducerKeys[i];
      var reducer = finalReducers[key];
      var previousStateForKey = state[key];
      var nextStateForKey = reducer(previousStateForKey, action);
      if (typeof nextStateForKey === 'undefined') {
        var errorMessage = getUndefinedStateErrorMessage(key, action);
        throw new Error(errorMessage);
      }
      nextState[key] = nextStateForKey;
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
    }
    return hasChanged ? nextState : state;
  };

Note: several lines of code are stripped for simplicity sake.

As you can see it is no longer using the reduce() as it was.

It is making certain optimization by considering whether the new state of the corresponding reducer has changed.

If one of the state changes, then it will return the whole new state. Otherwise if none changes ( nextStateForKey !== previousStateForKey keeps returning false ), it will return the previous state, and I assume there won't be any re-rendering.

Redux does this to ensure efficiency. Why re-renders if the state is equivalent as it was.

Due it's deterministic behavior, it will outputs the same result with the same input.

This leads to the question...

Why Pure Function?

As you saw in the preceding code, the combination() determines whether returning a new state is necessary through === operator, which is far efficient than a deep comparison.

Making any mutation to a state (and returning the mutated state) will make the comparison (hasChanged) results to false, which is not something we want to have (because a change HAS occur!).

Now.

One of the characteristic of pure function is it's prohibition to
mutate the arguments the function receives.

It matches exactly on how a reducer needs to be designed!

Every time a changes is made upon a state, a reducer has to return a new fresh state, and NOT making changes to the argument (previous state), therefore making it easier for Redux to tell whether it a change has occur.

It's that simple.

Encoding in 250 words

Computer speak in 1 and 0 (ones and zeroes), commonly referred to as binaries.

To produce character like A, 3, or ø it needs to know how to map each of those letters to binaries. Same situation applies when computer want to interpret data from binaries.

It may interpret a byte of 01000001 as A or perhaps B, depends on who sets up the rule in the first place.

Encoding basically a set of rule on mapping letters to binaries, and vice versa.

Know that a sequence of binary can be converted into to number (base 10) or hexadecimal (base 16). So keep it mind that a byte of 01000001 is equivalent to 65, and equivalent to 0x41 (0x indicates the that it’s a hex).

ASCII

One of the earliest encoding known is ASCII/ANSI.

They map decimal values from 0 to 127 to Western alphabets and control codes (tab, escape, backspace, etc) .

Mapping numerical values from 0-127 only takes up 7 bit of space. It does not specify numerical values from 128 to 255. So basically it wastes a bit for every byte. And it does not define characters for the rest of the world.

Unicode

Unicode isn’t necessarily an encoding but it does provide an interesting idea about code points.

All characters in the whole world is mapped to a form of U+WXYZ, whereas W, X, Y, and Z, are all hexadecimal values, which are able to hold numerical values 0-65535.

Now, there are several encoding to map this code points to real binaries:

  • UTF-7

  • UTF-8

  • UTF-16

  • UTF-32

Further readings:

Related concepts:

Using Redux Saga To Manage Your Side Effects

If you’re using Redux anytime by now, you’ll realize as your codebase goes large, so does your side effects. And by side effects I mean data fetching, or any async processes that needs special treatment.

Previously people would suggest to use redux-thunk, which basically is an action creator that returns a function, in which it will be invoked in your middleware. But it has it’s own challenges:

  • it’s not testable
  • no concurrency
  • the bigger the codebase, the more complicated it will be

Having Redux Saga as one of your dependency will tremendously makes life much easier as it abstracts complex async operation beneath the library’s core.

There are several prerequisite before proceeding to look for Redux Saga, you need to understand about generators and promises, better yet, async-await style.

This is because Redux Saga uses generators. Implementing a saga requires you to keep yielding stuff.

I suggest you to read the following beforehand:

Introduction

Redux Saga === Middleware

Yup, Redux Saga is just another kind of middleware that will intercept any of your dispatched action before handing it over to your reducer.

Getting Started

Because it’s a middleware, you need to specify your saga when creating your Redux store.

import {  
  createStore,
  applyMiddleware,
} from 'redux'
import createSagaMiddleware from 'redux-saga'  
import reducer from './reducers'  
import mySaga from './sagas'

// create the saga middleware
const sagaMiddleware = createSagaMiddleware()  
// mount it on the Store
const store = createStore( reducer, applyMiddleware(sagaMiddleware) )  
// then run the saga
sagaMiddleware.run(mySaga)  

This code is taken from the official documentation.

Watcher and Worker Saga

Generally you’ll have two kinds of saga:

  • Watcher Saga

  • Worker Saga

Watcher Saga watches for any incoming dispatched action.

When it receives one, it will spawns/initiate a worker saga, often referred to as a task, which will do the work.

I like to think a task as just another layer of middleware, but with a special ability of pausing and resuming.

Therefore, you can initiate multiple of worker saga/tasks at the same time, each will work concurrently.

Effects

You’ll see from the preceding code there’s a magic call  and put  invocation. call *and *put doesn’t directly invoke a function that does the work, instead it returns an instruction for the middleware to execute.

Here’s what it looks like:

{
  CALL: {
    fn: Api.fetch,
    args: ['./products']
  }
}

This kind of pattern is seen in a lot of libraries, including React’s React.createElement().

Redux Saga call this as an effect.

Call and put is two of several other effects Redux Saga introduces, but frankly you won’t need all.

Combining it all

Here’s what a typical watcher and worker saga would look like:

// defining your watcher saga
function* watcherSaga() {  
  yield takeLatest('FETCH_ALL_USERS_DATA', workerSaga);
}
// defining your worker saga
function* workerSaga(action) {  
  yield fetchResult = call(httpRequest);
  yield put({
    type: 'FETCH_RECEIVED',
    payload: fetchResult,
  });
}

Take a closer look on mySaga from the previous chunk of code, and that will be your saga’s starting point.

You’ll generally will always start with a watcher saga, it means that mySaga will be a watcher saga.

On this sagaMiddleware.run(mySaga) line of code, Redux Saga will directly runs your mySaga.

And what mySaga will generates is an instruction for the middleware!

So from the previous example, takeLatest will generate an instruction.

What does this instruction says?

It says to wait for the latest dispatched action FETCH_ALL_USERS_DATA, and when that action is dispatched, initiate the specified worker saga.

You can build your watcher saga like this:

function* watcherSaga() {  
  yield takeLatest('ACTION_A', workerSagaA);
  yield takeLatest('ACTION_B', workerSagaB);...and so on
}

Redux Saga flow on sagaMiddleware.run(watcherSaga) call:

  1. watcherSaga is called.

  2. watcherSaga will returns an instruction for ACTION_A.

  3. middleware receive the instruction then continues to run watcherSaga.

  4. watcherSaga returns another instruction for ACTION_B.

  5. middleware receives the instruction then continues to run watcherSaga.

This whole process will stop whenever a blocking effect is reached, commonly known blocking effects are:

  • call

  • take

Call returns an instruction to the middleware to call the given function (which has to return a promise). The middleware will wait until the promise resolves and then continue to run the saga.

Take returns an instruction to the middleware to wait for a specific action before proceeding the saga.

What I was just elaborating what happens when sagaMiddleware.run(watcherSaga) is called, which in essence, just to provide as many instruction to the middleware.

You can deep more in the official documentation here: http://yelouafi.github.io/redux-saga/

Or even try yourself the library which you can find here: https://github.com/yelouafi/redux-saga

Dissecting Redux (Part 3)

middleware implementation

Middleware sounds fancy, but it does nothing rather than wrapping your store.dispatch() function. The idea is to intercept your action before it reaches the original .dispatch() function.

So, how would you wrap it?

Well, it’s fairly simple.

You probably familiar with this pattern:

let a = 'string';  
let saveA = a;  
a = 'another string';</code>  

Instead of string, it saves the original store.dispatch() to a temporary variable, then assigns the store’s dispatch property to another function (middleware).

We might look it like:

let store = createStore();  
let originalDispatch = store.dispatch;  
let middleware = (action) => { //some awesome things to do here originalDispatch(action); } store.dispatch = middleware;  

When we’re up to dispatch an action, we end up invoking the middleware first.

The built-in middleware by Redux is way more robust than this one, but I assume it’s pretty clear from here, yes?

Now, what if we want to build several middlewares? We probably will have to reassign store.dispatch a couple times.

What if we want more and more middlewares? Our current approach is no longer reliable.

We need a better solution.

So here comes Dan’s approach, he built a function that performs the preceding block of code.

const wrapDispatchWithMiddlewares = (store, middlewares) => {  
  middlewares.slice().reverse().forEach((middleware) => {
    store.dispatch = middleware(store)(store.dispatch);
  })
}

Let’s take this on slowly.

Keep in mind that we need to inject a store and middleware to this function.

const store = createStore();  
const middlewares = [promise, logging]; // promise & logging is a function  
wrapDispatchWithMiddlewares(store, middlewares);  

Now, let’s analyze this bit of code: middlewares.slice().reverse().

He wants to slice() and reverse() for the sake of making promise middleware being the outermost middleware.

Slicing is done to prevent mutating the original array due to reverse().

You see, previously we set an array of middlewares, and as the list goes the array would become like:

[promise, logging, mw3, mw4, mw5, …].

It’s not so much of a big deal though, but the idea is to keep promise function to be the outermost (last evaluated).

For the next bits:

.forEach((middleware) => {
  store.dispatch = middleware(store)(store.dispatch);
})

Remember that the interpreter will evaluate this middleware(store)(store.dispatch) first.

Not to forgot what our middleware will look like, Dan come up with this functional form:

let middleware = (store) => (next) => (action) => {}  

This is called currying.

Basically, you just looping over: returning a function and calling it again.

The last function would then be able to access the store and next variable, thanks to closure.

Keep in mind that the middleware will end up looking like a usual dispatch function:

function middleware(action) { // statements }  

What differs is that it ables to access store and the previous store.dispatch.

Back to our middleware, we’ll invoke each of the middleware, passing reference to our store, and the previous store.dispatch. Then, assigning our middleware as the new store.dispatch. This happens over and over until our list of middlewares runs out.

Seeing from our middleware, our next will be the previous store.dispatch.

You can picture this as peeling an onion, every layer is a middleware, and the innermost layer is the original store.dispatch that has the ability to invoke the reducer.

Dissecting Redux (Part 2)

combineReducers implementation

As the name goes, this built-in function by Redux is use to get your reducers combine together.

const combineReducers = (reducer) => {  
  return (state = {}, action) => {
    return Object.keys(reducers).reduce((nextState, key) => {
      nextState[key] = reducers[key](state[key], action);
      return nextState;
    }, {});
  };
}

If this seems overwhelming, you might want to check this one, it does the same thing (with manual configuration).

const combineReducers = () => {  
  return (state = {}, action) => {
    return {
      substate1: subReducer1(state.substate1, action),
      substate2: subReducer2(state.substate2, action),
    };
  }
}

combineReducers produces a reducer that takes a state and an action

But instead of manipulating the state based on action it received, it passes the same action and a small portion of the state to another reducer (subReducer1, subReducer2), and let them handle it for you.

The resultant would be part of the next state.

combineReducers basically includes a reducer with another reducer. That’s why reducers are awesome. It’s composable.

If you when through the first implementation. Dan Abramov, the creator of Redux, use .reduce() method built-in into arrays. That’s why he named it reducer in the first place.

You might notice that he uses Object.keys() over for … in to traverse among reducers (object).

That is because it’s more efficient. You see, for … in traverse all methods/properties including their prototypes, so it’s kinda sucks.

Object.keys() generates an array of containing list of your object’s key.

Now, back into .reduce().

That method accepts two arguments, the second one is optional. The first one is a callback.

What it does is it evaluates over two values at a time (starting from index zero, so it initially it evaluates index zero and index one), the result would be evaluated to the next index, until it results into a single value.

It will not start from index zero if you specify an initial value (second argument), instead it will evaluate that initial value with your index zero.

In this case, Dan specifies an empty plain object as an initial value. He will keep passing this object as the result of the evaluation.

Now, what he does using that plain object/object literal — {} is fairly the same as you would see in the second implementation.

It calls the reducer:

reducers[key](state[key], action)  

and assign it to the corresponding key nextState[key] . Notice that *nextState *is the plain object we specify earlier.

Extra

If you’re still new to reducer, it’s basically a function that accepts previous state and an action, and returns a new state.

It has to be pure, which means you can’t mutate your arguments, because it might affect other reducers in an interesting way.

function reducer(prevState = {}, action) {  
  switch (action) {
    case 'ACTION_1':
      doSomething();
      break;
    case 'ACTION_2':
      doSomething();
      break;
    default:
      return prevState;
  }
}

This block prevState = {} means that if it receives undefined value, then it will assigns prevState with {}. We use it to supply the reducer with an initial state, we do this because initially our store will dispatch an empty action — thus undefined.

The default statement is necessary in case your reducer has no idea how to deal with the action, so you’ll just return the same state as it was.

How Browser Rendering Works

I guess it’s pretty important to figure how the browser actually works behind the scene.

We all know how to write HTML, CSS, and JavaScript. But how do browser actually use those languages to actually produce something useful to the user?

I didn’t know the answer profoundly though, but I discover several interesting sources you may want to checkout!

Reflow & Repaint is a useful concept the browser implements whenever changes occur. It is important for you to consider because it affects your web performance.

This is my conclusion for the preceding articles.

Big Picture:

DOM + CSSOM –> Render Tree –> Layout –> Paint

HTML parsed to a DOM (Document Object Model). I believe it contains information like type of the node and attributes (so it include inline style, and mutable using the domNode.style).

CSS parsed to a CSSOM (CSS Object Model).

Together, DOM and CSSOM blends into Render Tree.

The browser layout each node of the Render Tree, then paints them to the page.

Repaint is a concept where the browser repaints your node to the page.

Reflow is when the browser relayout your node, and then repaints it back, so it’s considered more expensive.

I believe changes occur because we mutate the DOM, not the Render Tree (I mean, changes to the DOM reflects to the Render Tree, but we can not directly change the Render Tree).

What expensive for the browser:

  • Multiple pass

  • Multiple node needed to reflow & repaint during each pass

And by mean pass is the rendering flow.

So multiple pass means multiple rendering flow.

One of the article mention that the browser is smart enough to cache changes before actually do an actual rendering.

So if you update a single node using several statement in JavaScript, the browser will cache the changes first, then when all your statement ends the browser will implement all the changes in a single pass.

Important to note is if you’re reading a DOM node, it will force a reflow, and your cache will directly be implemented.

Studies Are Just Studies

These days more and more scientific studies are being performed and released.

Internet is giving us favor to access those scientific results. They spread much faster than ever before.

Some studies produce new insight, but many are born only to deny previous one.

What we thought was true, turns out to be not so accurate.

This lead me to a conclusion that studies are just studies.

They once told us that we only use 10% of our brain.

They once told us that there is a left-brain and a right-brain.

They once told us that eating MSG makes you stupid.

They once told us that IQ can measure your intelligence.

The list goes on…

I always feel nauseous about this whole concept of IQ test that can measure your intelligence. It just doesn’t sound right.

What I know is that if you’re a 10 year old kid with a brain of an 18 year old, that would result to a shocking 180 IQ score.

But when you’re 18, you took another test, and results with a brain of your current average peers, well, your IQ had just declined to a staggering 100.

Are you smarter? No.

Are you dumber? No.

I can even assure you that your score is subjective. If you take an IQ test A and IQ test B, or taking your test in the morning or at night, results will be varies.

IQ test oversimplifies your intelligence.

I strongly believe that determining intelligence is to measure the amount of neurons and neuronal connections, their locations, firing patterns and rates, and plasticities.

It ain’t that simple too though. It will and always be more complex than what we know now.

Always conceive with a grain of salt. Never believe wholeheartedly.

Some sources:

Dissecting Redux (Part 1)

Redux act as an architecture for the React library. It improves Flux whereas Flux improves common MV* pattern used among lots of client-side frameworks like Angular.

While MV* pattern usually went for two-way data binding, where both model and view can simultaneously change one another, Redux doesn’t work that way.

It leverages React’s unidirectional flow (parent-child one direction data flow), therefore makes your code easier to reason about, especially when your codebase goes large.

There are several main ideas on Redux:

  • It isolate I/O and data fetching
  • One source of truth (state)
  • Only state can change the view
  • Immutability

Instead of old-fashion event-driven sourcing, Redux (and Flux) wraps an event as an action, plain object which describe the type and correspond data. It enables I/O and data fetching response to not directly alter your view. It queues as an action.

So, whenever a button is clicked, user type into a text box, or data from server received, an action is dispatched. Any component can also dispatch an action.

That action will be received by the dispatcher and pass to something called as the reducer. What a reducer does is it handles your state. It may or may not changes your state. It receives both an action and previous state, then returns a new state.


View –> Action –> Dispatch –> Reducers –> View

Any React component (View) can dispatch any action, which will be received by the dispatcher, then it will be passed to the reducer which will change your state. Any changes to your state will be reflected to your View (UI).

Always keep in mind that your View is a reflection of your state. Ideally, your View will re-renders every time the state changes.


createStore() implementation

const createStore = (reducer) => {  
  let state;
  let listener = [];
  const getState = () => state;
  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach(listener => listener());
  }
  const subscribe = (listener) => {
    listeners.push(listener);
    return () => {
      listeners = listeners.filter(l => l !== listener);
    };
  };
  dispatch({});
  return {
    getState,
    dispatch,
    subscribe,
  };
};

The code might not look exactly as above, but the idea stays the same.

The store leverages factory to make store instances, and make use of closure. So instances return from createStore() will have a .getState() ,dispatch() , and subscribe()  functions.

By closure means that even though createStore() function has popped/exited, it’s variable environment (meaning all variables created inside the function scope) will not be thrown away (by garbage collector) and still accessible by any execution context (function) generated inside the createStore().

.getState() is a getter to get your current state.

.dispatch() is the method which will handle your dispatching need. It receives an action, and will pass that same action to the reducer. The reducer will generates a new state that will be re-assigned to the state.

.subscribe() defines what you’d like to do after your state changes. It pushes a function to the listener array where that array will be iterated at the end of the dispatch function.

Notice that there is an empty action triggered by dispatch({}) at the bottom (although it will pass something different now)? The idea is to trigger default argument in the reducer, so you can specify an initial state for your store.

We’ll continue several implementation on the next part.