Digital Transformation in HealthCare Solution

Tech Talk

Redux Rematch - State Management

02 SEPT 2021

Rematch is an enhanced version of Redux with added few more features, clean architecture, less boilerplate for React Developers. Rematch uses the same redux concept and also has a persistor to persist store data.

Please download full source code from our GitHub.

Let’s look into architecture,

Redux Rematch Architecture


export default init({
    models,
    plugins: [loadingPlugin, persistPlugin],
    redux: {
      middlewares: [logger],
    },
  })  
Redux Rematch Architecture

Provider -


<Provider store={store}>

Provider contains an argument store. Here, we need to pass our store object in store argument to initialize Rematch Store.

Store -

To initialize a store we need to pass models, plugins, redux, etc. Let’s check the syntax,


export default init({
    models,
    plugins: [loadingPlugin, persistPlugin],
    redux: {
      middlewares: [logger],
    },
  })  

Models - Models contain state, reducer and effects in one instead of separate like Redux.

Plugins - Plugins contain Loading Plugins, Persist Plugins.

Redux - Contains middleware to perform some action in middleware between store & frontend.

Models -

Models are the core part of Store. Model contains state variables, reducers, effects. Frontend will dispatch action, which executes in effects and once effect computed task it will dispatch to reducer and reducer is responsible for updating state variables. So whenever the state variable is updated our component is also notified.

As you can see in Image, when UI Dispatch action it executes effects in model, once effect completed its execution it dispatches to reducers and reducer is only responsible to update state. Once the state gets updated it will re-render the UI Component.


export const TaskList = {
    state: {
      arrTasks: [],
      fetchError: undefined
    },
    reducers: {
      setTasks(state, payload) {
        return {
          ...state,
          arrTasks: payload,
        };
      },
      setError(state, payload) {
        return {
        ...state,
        fetchError: payload
        }
      }
    },
    effects: (dispatch) => ({
      async fetchTaskList() {
        try {
          const data = [
              { "taskID": 1, "taskName": "Task #1" },
              { "taskID": 2, "taskName": "Task #2" },
              { "taskID": 3, "taskName": "Task #3" }
          ]
          dispatch.TaskList.setTasks(data);
        } catch (error) {
          dispatch.TaskList.setError(error);
        }
      },
    }),
  };

Plugins -

Rematch allows various plugins, you can set Loading Plugins, Persist Plugins.

Loading Plugins -

When we dispatch any action, we have to wait for a fraction of time until we receive results (API Call, Local Operation). Redux in-built having plugins that manage and return us loading = true which effect (action) being in-progress.

You can create Loading PlugIns using createLoadingPlugin, and pass your model name/actionname in the whitelist. As you can see we have taskList (model), fetchTaskList (action). So after this code, whenever the fetchTaskList operation is in-progress we will get loading as true, once it’s completed we get loading as false.


import createLoadingPlugin from '@rematch/loading';

export const loadingPlugin = createLoadingPlugin({
  whitelist: [taskList/fetchTaskList'],
});

Persist Plugins -

Persist Plugins contains all required configuration like, whitelist, blacklist, version, storage, transforms, Let’s discuss each in details,

whitelist - Specify a list of models which you want to store in storage, even though you kill an application, restart application.

blacklist - Specify list of models which you don’t want to store in storage, so next time it will load with initial state, instead of saved state.

version - version of store,each to you deploy new application increase the version number, which help to migrate data from older version to newer version.

storage - Specify the storage when your store data is saved, for mobile applications ideally we prefer AsyncStorage, while in web we prefer default Web Storage.

transform - Specify Filters, many times you are required to blacklist a model (don’t want to store state value/ persist state value) but you want to store a few key/pairs only. So you can create whitelist filters for a few keys, and pass the model name in blacklist. So Rematch will only store key/pairs which you have sent in the whitelist.

Redux -

Redux contains middlewares, you can specify middlewares. You can create your own middleware to perform some action between UI Component and Effect which action dispatch by UI Component.

For example, let’s specify logger as middleware, so when you dispatch action, it will log in the console to track actions, same way whenever reducer updates the state at the same time logger also logs in console to update users about Rematch actions.


import logger from 'redux-logger';
redux: {
  middlewares: [logger],
}

Now Let’s take an example of a Model and dispatch actions from the Component.

Model - TaskList.js


export const TaskList = {
    state: {
      arrTasks: [],
      fetchError: undefined
    },
    reducers: {
      setTasks(state, payload) {
        return {
          ...state,
          arrTasks: payload,
        };
      },
      setError(state, payload) {
        return {
        ...state,
        fetchError: payload
        }
      }
    },
    effects: (dispatch) => ({
      async fetchTaskList() {
        try {
          const data = [
              { "taskID": 1, "taskName": "Task #1" },
              { "taskID": 2, "taskName": "Task #2" },
              { "taskID": 3, "taskName": "Task #3" }
          ]
          dispatch.TaskList.setTasks(data);
        } catch (error) {
          dispatch.TaskList.setError(error);
        }
      },
    }),
  };

Component - Tasks.js


import React, {useEffect} from 'react';
import {
    SafeAreaView, View, FlatList, Text
} from 'react-native';
import { connect } from 'react-redux';

function Tasks(props) {

    useEffect(() => {
      props.fetchTaskList();
    }, []);

    const TaskListItem = ({task}) => {
      return (
        <View style={{flex: 1, marginVertical: 10, marginHorizontal: 10}}>
          <Text>{task.taskName}</Text>
        </View>
      )
    }

    console.log(JSON.stringify(props.arrTasks));

    return (
      <SafeAreaView style={{flex: 1}}>
         <FlatList
            data={props.arrTasks}
            renderItem={({ item, index }) => <TaskListItem task={item}/>}
            keyExtractor={(item, index) => item.taskID}
        />
      </SafeAreaView>
    );
  }
  const mapStateToProps = ({ TaskList, loading }) => ({
    arrTasks: TaskList.arrTasks,
    loading: loading.effects.TaskList.arrTasks,
  });
  
  const mapDispatchToProps = ({ TaskList: { fetchTaskList } }) => ({
    fetchTaskList: () => fetchTaskList(),
  });
  
  export default connect(mapStateToProps, mapDispatchToProps)(Tasks);

As you can see in Tasks Component, We are dispatching fetchTaskList on load of Component. Will call effect in TaskList.js model. Once fetch operation completed it will dispatch setTasks (action), which calls function in reducers, and reducer will update state variables of arryTasks, which in result re-render our Tasks Component.

Please download full source code from our GitHub.

Thanks for reading Blog!

Want to receive Tech Articles!

Get tech aricles directly in your inbox! Share your email with us and receive tech articles as instant as we publish!

KPIENG

KPITENG

DIGITAL TRANSFORMATION

Want to talk about your project?

  • INDUSTRY
  • E-Commerce & Shopping
  • Healthcared & Fitness
  • Banking & Finance
  • Education
  • Logistics & Distribution
  • Social Networking
  • Real Estate
  • Food & Restaurant
  • On-Demand Services
  • Media
  • IT & Telecom
  • Productivity

Want to talk about your project?

© 2023 KPITENG, all rights reserved