Saturday, July 31, 2021

Wait for State Changes with Redux Saga

Hello,

As we know Redux saga allows us to respond to actions outside Redux store. It's kind of middleware library to handle side effects with ease. This side effect could be anything like calling APIs, doing some IO operations or anything. While working with Saga sometime it happens that we also want to detect state changes and do some actions after it. In this blog I am going to explain how you can wait or detect Redux state changes with Saga.

Let's understand with an example. For example there is an API call to get access token and as soon as you have access toke available in state you want to call some other actions like background sync etc. 


function* waitForLoginToken(selector) {

    if (yield select(selector)) return;

    while (true) {

      yield take('*');

      if (yield select(selector)) return;

    }

}

export function* postSignInAction(payload) {

    cost loginTokenSelector = state => state.auth.loginToken;

    yield call(waitForLoginToken, loginTokenSelector);

    yield put({ type: 'BACKGROUND_SYNC' });

}

function* mySaga(){

  yield takeEvery('SIGN_IN', postSignInAction);

}

As you can see in above code, we take every sign in action and call postSignInAction which will wait for state change.

We defined state selector as state.auth.loginToken. Till the time loginToken is not set in state.auth it will wait as we are using while loop to wait for state change. Once we get it in state we call next action. 

This way you can & detect state change with Redux Saga. Hope this helps you.

Saturday, July 17, 2021

React-Draft-Wysiwyg - Find Text Option

Hello,

Recently I was working on POC for rich text editor using React-Draft-Wysiwyg editor. 

There we have a requirement to add find & replace dialog box which should find the matching text from all the blocks and height it with background color. For the POC we added find text functionality. Here in this blog I will explain how to do it. 

For this I have created separate React component and add it as custom option to editor toolbar. Let's understand it step by step. 

If you want to know how to add custom option you can find reference from here.

https://jpuri.github.io/react-draft-wysiwyg/#/docs

1) Create Modal with Text input and Button

Please note I have used grommet UI library to build the POC. So text input and button was imported from Grommet.

<TextInput

    data-cy="find-text"

    autoFocus

    onChange={this.onChangeFindText}

    value={this.state.findText}

/>

<Button

    id="find"

    label="Find"

    onClick={this.onFindClick}

/>

2) Handle Find Click Event

onFindClick = () => {

  const search = this.state.findText;

  let contentState = convertToRaw(this.props.editorState.getCurrentContent());

  contentState.blocks.forEach(block => {

    const text = block.text;

    const matches = [...text.matchAll(search)];

    if(matches.length > 0) {

      matches.forEach(match =>{

        block.inlineStyleRanges.push({length: match[0].length,

          offset: match.index,

          style: "bgcolor-rgb(247,218,100)"

        })

      });

    }

  });

  let newEditorState = {

    editorState: EditorState.createWithContent(convertFromRaw({blocks: contentState.blocks,entityMap: {}})),

    contentState: null

  }

  this.props.onChange(EditorState.createWithContent(convertFromRaw({blocks: contentState.blocks,entityMap: {}})));

}

In above code we are getting search text from the state and matching it with texts of all custom blocks. Where ever it matches we are setting inline styles in blocks with yellow color background. and then setting state of editor again with new blocks. 

Hope this helps you.

Sunday, July 4, 2021

Docker MongoDB terminates when it runs out of memory

When you have multiple services running in docker container it's quite possible that you have an issues with certain services when your docker container runs out of memory. MongoDB is one such service. 

On docker container when you have MongoDB running and when it starts storing huge data it starts consuming lots of memory and that's where you have an issue. MongoDB will crash after sometime where isn't much memory left. 

The reason behind this is the IO model of MongoDB, it tries to keep as much data as possible in cache so read and write operations are much faster. But this creates an issue with docker as we have limited memory and lots of services are sharing that. 

Starting from MongoDB 3.2 on words WiredTiger storage engine is the default one for MongoDB and it's recommended. 

There are various advantages of WiredTiger storage engine. For example,

  • Document Level Concurrency
  • Snapshots and Checkpoints
  • Journal
  • Compression
  • Memory Use
One of most useful feature is Memory use. 

With WiredTiger, MongoDB utilizes both the WiredTiger internal cache and the filesystem cache.

You can control it with --wiredTigerCacheSizeGB configuration.

The --wiredTigerCacheSizeGB limits the size of the WiredTiger internal cache. The operating system will use the available free memory for filesystem cache, which allows the compressed MongoDB data files to stay in memory. In addition, the operating system will use any free RAM to buffer file system blocks and file system cache.

With this setting you can enhance memory usage. MongoDB will not use excessive memory and with heavy data usage on docker container MongoDB will not crash on excessive memory usage.

Hope this helps you.

ReactJs Peer to Peer Communication

Recently I evaluated peer to peer communication approach for one of my project so here I am going to share it and how you can use it in your project in case you want to implement peer to peer communication in your project. 

We used library called PeerJS , it's simple peer to peer built on top of webRTC. For this first you have to create a server, which will act as only connection broker. No peer to peer data goes through this server. Let's just create a simple server.

Let's first install peer from npm. 

npm install peer

Now let's create NodeJs script. 

const { PeerServer } = require('peer');

const peerServer = PeerServer({ port: 9000, path: '/server' });

peerServer.on('connection', (client) => { 

console.log(client);

});

That's is now you can run this script through terminal and it will run your server on 9000 port.

Now let's connect to server from our ReactJS component. 

First lets install peerjs npm which is peer client. 

npm install peerjs

We can connect to server in componentDidMount method and add some callbacks function.

import Peer from 'peerjs';

componentDidMount = () => {

        this.peer = new Peer("USERNAME", {

          host: 'localhost',

          port: 9000,

          path: '/server'

        });

        this.peer.on("error", err => {

            console.log("error: ", err)

        })

        this.peer.on("open", id => {

            console.log(id)

        })

        this.peer.on("connection", (con) => {

            console.log("connection opened");

            con.on("data", i => {

                console.log(i)

            });

        })

}

In above code first function is the error callback function. Second once is when peer connection is opened. Third one is when you receive connection from some other peer and get some data. 

Now let's take an example of how you can connect to other peer and send data. 

const conn = this.peer.connect('REMOTE_PEER');

conn.on('open', () => {

          conn.send('DATA');

});

In above code we are connecting to some remote peer and sending some data to it.

Please note here peer to peer data goes through ICE server which you can setup and assign when you create peer server or else it will use PeerCloud server by default. For the development purpose that's ok but for the production you should create your on TURN or STUN server.

Hope this helps you in setting up