Redux in a nut shell

What is Redux?

Redux is a predictable state container for JavaScript apps.

In this tutorial we will create an awesome Redux app in organized fashion. But at first we will create an app in single file, analyse it and break it down to more manageable chunks of components and organize it in a comprehensible dir-structure.

Project Setup

initialize a node.js app using npm.

$ npm init

install redux, webpack, webpack-dev-server, babel(with loaders)

$ npm i redux -S
$ npm i webpack -D
$ npm i webpack-dev-server -D
$ npm i babel-loader babel-core babel-preset-es2015 -D

update the file package.json

 "scripts": {
 "start": "webpack-dev-server --config=webpack.dev.config.js"
 },

Configure the webpack-dev-server like

# webpack.dev.config.js
module.exports = {
  entry: ["./src/index.jsx"],
  output: {
    filename: "bundle.js",
    path: __dirname + '/public'
  },
  devServer: {
    contentBase: './public',
    port: 3000
  },

  module: {
    loaders: [
      {
        test: /\.js[x]?$/, // Allowing .jsx file to be transpiled by babel
        exclude: /(node_modules|bower_components)/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015']
        }
      }
    ]
  },
};

Now you will need to have a index.html which will load your JS app in browser.

<!-- in public/index.html -->
<html>
  <head>

  </head>
  <body>
    
Hello world
/bundle.js </body> </html>

And, to start a http server you do

$ npm start

goto http://localhost:3000 to see your app in the browser.

See this pull request for more info

Live reload setting using webpack-hot-middleware

Oops I forgot to install the hot-loader plugin that would auto reload the components as soon as you save the source-code file.

“Hot Module Replacement” (HMR) is a feature to inject updated modules into the active runtime.

It’s like LiveReload for every module.

$ npm install --save-dev webpack-hot-middleware
# or
$ npm install -D webpack-hot-middleware

// In webpack.dev.config.js you need to make some changes
const webpack = require('webpack');
module.exports = {
  entry: [
    "./src/index.jsx",
    "webpack-dev-server/client?http://localhost:3000/",
    "webpack/hot/only-dev-server"
  ],


  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ]
}

If config is good you will see like HMR] Waiting for update signal from WDS... in the browser console. This indicates that an active websocket connection is there to listen to any changes you make back there.

See this pull request for more info.

Now Redux starts moving!

gyxjrhtmudynp2jhvtud

See this Commit for a simple redux app in action. You see a simple Redux application changing its state using reducer and listening via subscribing to the Store. You can pass a callback function to perform some action when state is changed.

Reducer is a pure function that takes in previous_state and returns new state.

import {createStore} from 'redux';

// Reducer is a pure function that takes in previous_state and returns new state
const reducer = (prev_state, action) => {
  var new_state = {};
  if (action.type === "INC") {
     new_state.tweetCount = prev_state.tweetCount + 1;
   } else if (action.type === "DEC") {
     new_state.tweetCount = prev_state.tweetCount - 1;
   } else {
     new_state = prev_state;
   }
  return new_state;
};

const seedData = {
  tweetCount: 5
};

// Now we create a store where we will keep our application's state
const store = createStore(reducer, seedData);
const listener = () => {
  console.log("The tweet count is now ", store.getState().tweetCount);
};

store.subscribe(listener);

store.dispatch({type: "INC"});
store.dispatch({type: "DEC"});

Explanation of the workflow; assuming you have a store set already:-

  • Firstly, you/user decides which action to perform; may be he will click some “Tweet” button in the UI
    • Corresponding ACTION will be “INC”
    • Action must always be a JSON like {type: ‘something’}
    • Must contain the key “type
  • Secondly, you dispatch the action using dispatch method in store object
  • Internally, the store calls the reducer function you introduced to the store as a parameter to createStore function.
    • The params available inside the reducer function are current_state object [or you may say prev_state]
    • And, action triggered by the User
    • Reducer processes the request, creates a new state object with necessary changes asked by the UI and return the new_state
    • Then, the store updates the current_state but does not overwrite. No mutation happens whatsoever.
  • Finally, the application’s state is updated; You might want to know when its happen so you subscribe to the broadcast using a listener function.
    • This listener function you pass to the store is executed when the event occurs.
    • It a callback function

 

Components Breakdown

In a long run our application will definitely grow and can become a big ball of mud. So, we should take care in infancy to raise a better child. Little bit of grooming is necessary over here.

In example above we had no complex state to worry about; just tweetCount. Normally in real-world project we have state like

{
  users: [
    {id: 1, first_name: 'John', last_name: 'Kelly', age: 34, email: 'john@sedd.com'},
    {id: 1, first_name: 'Peter', last_name: 'Kelly', age: 34, email: 'john@sedd.com'},
    {id: 1, first_name: 'Ramesh', last_name: 'Chapagain', age: 34, email: 'chaps@sedd.com'},
    {id: 1, first_name: 'Dinesh', last_name: 'Banjade', age: 34, email: 'banz@sedd.com'},
  ],
  articles: [
    {id: 1, author_id: 1, title: 'Beautiful country Nepal', body: "Lorem Ipsom", tags: 'sdsd, asd, as, d'},
    {id: 2, author_id: 1, title: 'Beautiful country Nepal', body: "Lorem Ipsom", tags: 'sdsd, asd, as, d'},
    {id: 3, author_id: 3, title: 'When I visited Dharan', body: "Lorem Ipsom", tags: 'sdsd, asd, as, d'},
    {id: 4, author_id: 4, title: 'My trip to Everest Basecamp', body: "Lorem Ipsom", tags: 'sdsd, asd, as, d'}
  ],
  ...
}

So, maintaining such a mess is a nightmare so now we will see how to organize the reducers.

Here is a gist to exhibit the chaos when everything is in a single file. Or you can have a look into this Pull Request.

Managed Directory structure

See this pull request 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s