Integrating Redux with SUSI.AI Web Clients
In this blog post, we are going to go through the implementation of the Redux integration on the SUSI.AI web clients. The existing SUSI.AI WebChat codebase has Flux integrated into it, but integrating Redux would make it a lot easier to manage the app state in a single store. And would result in a more maintainable and performant application. Let us go through the implementation in the blog - The key steps involved the following - Restructuring the directory structure of the repository to enable better maintenance.Creating a Redux store and configuring the middlewares.Standardizing the format for writing actions and make API calls on dispatching an action.Standardizing the format for writing reducers.Hook the components to the Redux store. Restructuring the directory structure DIrectory structure for https://chat.susi.ai All the redux related files and utils are put into the redux directory, to avoid any sort of confusion, better maintenance and enhanced discoverability. The prime reason for it also because the integration was done side-by-side the existing Flux implementation.The actions and reducers directory each has a index.js, which exports all the actions and reducers respectively, so as to maintain a single import path for the components and this also helped to easily split out different types of actions/reducers. Creating Redux store and configure middlewares import { createStore as _createStore, applyMiddleware } from 'redux'; import { routerMiddleware } from 'react-router-redux'; import reduxPromise from 'redux-promise'; import reducers from './reducers'; export default function createStore(history) { // Sync dispatched route actions to the history const reduxRouterMiddleware = routerMiddleware(history); const middleware = [reduxRouterMiddleware, reduxPromise]; let finalCreateStore; finalCreateStore = applyMiddleware(...middleware)(_createStore); const store = finalCreateStore( reducers, {}, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), ); return store; } The function createStore takes in the browserHistory (provided by React Router) and returns a single store object that is passed on to the entry point component of the App. The store is passed to the application via the <Provider> component, provided by the react-redux. It is wrapped to the <App> component as follows - ReactDOM.render( <Provider store={store} key="provider"> <App /> </Provider>, document.getElementById('root'), ); The 2 middlewares used are routerMiddleware provided by the react-router-redux and the reduxPromise provided by redux-promise.The routerMiddleware enhances a history instance to allow it to synchronize any changes it receives into application state.The reduxPromise returns a promise to the caller so that it can wait for the operation to finish before continuing. This is useful to assist the application to tackle async behaviour. Standardizing the actions and making API calls on action dispatch The actions file contains the following - import { createAction } from 'redux-actions'; import actionTypes from '../actionTypes'; import * as apis from '../../apis'; const returnArgumentsFn = function(payload) { return Promise.resolve(payload); }; export default { // API call on action dispatch getApiKeys: createAction(actionTypes.APP_GET_API_KEYS, apis.fetchApiKeys), // Returns a promise for actions not requiring API calls logout: createAction(actionTypes.APP_LOGOUT, returnArgumentsFn), }; As new actions are added, it can be added to the actionTypes file and can be added in the export statement of the above snippet. This enables very standard and easy to manage…
