Javascript

React Tips

React Tips

React is nowadays taking a big part of my development life as I lead the frontend team in my work place. I always encounter small tips when searching for solutions and I never remember them. I decided to store this information in this blog post rather then in some private doc so other people can benefit from this.

Hooks – useState

Merge Previous State

The useState hook doesn’t do merge with previous state as setState does in class components. If you initialize state with:

const [state, setState] = useState({
    hi: 'bye',
    yo: 'dawg'
});

and you perform

setState({ yo: 'dude' });

state will become

{
  yo: 'dude'
}

instead of

{
  hi: 'bye',
  yo: 'dude'
}

You can do merge by yourself with the spread operator as here:

setState(prevState => ({ …prevState, …{ yo: 'dude' } }));

Function state updater

Previous section leads to the question why there are 2 way to update state, by passing a value as first prop or by passing a function. Consider the following classic counter component, but this time I want to hack my counter to increase by 2:

const CharacterCounter = () => {
  const [count, setCount] = useState(0);
  
  const increaseBy2 = () => {
    setCount(count + 1);
    setCount(count + 1);
  };
  
  return (
    <div>
      <div>count: {count}</div>
      <button onClick={increaseBy2}>++</button>
    </div>
  );
};

You can run the code in here. Button click increment the counter only by one at a time. Count is only calculated once when we call useState and will be recalculated only the next render, so we basically pass the same value to the updater function that will actually update count only in the next render. It will be clearer if we change the increaseBy2 function to something like this:

  const increaseBy2 = () => {
    const next = count + 1;
    setCount(next + 1);
    setCount(next + 1);
  };

Another use case could be if your value is captured in a closure, and will be ‘cached’ with initial value. So to avoid this, it is a good practice, in my opinion, whenever you have update state function and it depends on previous state, pass update function.

const CharacterCounter = () => {
  const [count, setCount] = useState(0);
  
  const increaseBy2 = () => {
    setCount(prevCount => prevCount + 1);
    setCount(prevCount => prevCount + 1);
  };
  
  return (
    <div>
      <div>count: {count}</div>
      <button onClick={increaseBy2}>++</button>
    </div>
  );
};

Link to a working example.

React Context API

Using React Context as a global state manager

I was so enthusiastic with React Context API when I first used it so I had some great ideas how to make my applications use it as a global state manager. With the release of hooks API it was even more exciting and I ran to build my own state manager based on some ideas I had and read about across the web. Mainly I was inspired by this blog post. I added some more abstraction from my side to make the API look something like I used before and liked very much, vuex as part of my experience with VueJS.

Everything looked great until I opened the react dev tool. The whole application was re-rendering with every change in my global state. That is something that of course can lead to performance issue as application grows, and even though the application I built was pretty small, I couldn’t sleep thinking about those unnecessary renders. So 3 blog post made me think differently about small-mid application state management and I suggest you to read them:

  1. Global state with React
  2. Application State Management with React

What I realised after reading those blog posts is that context API is not a solution for managing a large-whole-app global state. Even when I tried to use useReducer, useCallback, useMemo and other cache methods it was not what I wanted. It always ended with dealing with the fact that changing context will re-render all parts using eventually my custom wrapper hook for useContext and useReducer. The final needle was when I read that react-redux project had performance issues with context based state management.

Finally what I decided for now is still to use React’s context API but more closely to the component that needs it, and even then, consider carefully if you even need it. I am still investigating how to get to the perfect spot of managing a small-mid size application without any 3rd party library which always add a lot of boiler plate, I will update for sure.

JavaScript Asynchronous Life Cycle Simply Explained

JavaScript Asynchronous Life Cycle Simply Explained

JavaScript has a lot of power today. It drives all the front end applications on browsers, delivers back end applications (NodeJS) and more. JavaScript is not exceptional from other programming domains, means that as a JavaScript professional developer you have to know a few things about the internals of the language in order to create great applications. There are few misconceptions and lack of knowledge that some JS developers face along their career, and gathering this knowledge and breaking those misconceptions can of course help them to create even greater products. In this post we will bust the myth of “JavaScript is Asynchronous”.

JavaScript Is Not Asynchronous

The most common misconception among JS developers is that JS is asynchronous language. Actually I cannot think of a programming language that indeed is asynchronous, and what the hell does that mean “Asynchronous Language” anyways?

Asynchronous term in JavaScript is related to the way of JS deferring tasks to execute in a later stage of code run time. The way JavaScript runs it asynchronous calls are handled by the context in which JavaScript is running (browser, NodeJS, etc). For example the most simple asynchronous function setTimeout is not native JavaScript function, it is implemented differently in the browser and in nodeJS. Actually JavaScript is processing and executing it’s commands one line at a time, line by line, or in other words it is a “synchronous language” or in the real word terms: blocking single thread programming language. To examine this write a small program with a big while loop followed by a console.log, you can see that the console.log isn’t executed until the loop finished.

There are a few ways to deal with asynchronous tasks (such as reading and writing to database, dealing with OS I/O, etc). Callbacks, promises and async/await functions and more, are the way JavaScript enables you to execute asynchronous tasks and get back the responses. Those all are a syntactic way to deal with those problems, but what happens behind the scenes?

Behind The Scenes

The part that manages The execution logic called the V8 engine, you might have heard about it here and there in the context of chrome browser and NodeJS. V8 is the JavaScript engine that drives the chromium project (chrome browser is based on chromium). NodeJS is implemented on top of V8 also.

Stack

When we execute synchronously our code, line by line, yes, even your asynchronous functions, they are pushed into something called the stack. I won’t get too much into details here. In short, each function call creates a space in memory called frame that contains all information for it to be executed, for example the arguments, and this fame is pushed to the top of the stack. When the function returns, its frame is popped out of the stack. Using a stack is a very familiar way to deal with synchronous operations, because you can tell exactly when a function is running and when it is returned. Actually you might have used this stack when debugging your application. When you get an execution error on the browser for example, you can see the stack trace is printed out, this is easily done because of the stack data structure. And of course the mighty stack overflow error is thrown when the stack gets bloated with too many frames, in chrome browser the limit is 16000 frames.

Heap

The heap is a region in the memory where arbitrary data can be stored in 
unordered way. (The ECMAScript language specification doesn’t specify definition on memory layout, so what does it in real life is the interpreter). In other words, V8 (written in c++) handles memory allocation in a way that it allocates the memory in the heap and uses pointers to those variables in the stack which is much more ordered and fast. V8 engineers of course made a lot of optimizations to this abstract review I wrote, so for example atomic variables such as booleans are actually stored in the stack, and much more optimizations also done in this engine. The heap has also to do with the Garbage Collector but we will leave this to another post.

Queue

The queue is the core of this post. The queue is a place in memory which queues messages associated with the asynchronous tasks (callbacks) created by your program. If a callback is not created, no message is pushed into the queue, for example mouse move events without callbacks. The messages in the queue are processed in order (FIFO) as the stack gets empty (or other logic implemented by the interpreter), and what manages this execution is something called the Event Loop.

The event loop is (as the name suggests) an infinite while loop that queries the stack and the queue for tasks to do. When the stack gets empty it takes the next task from the queue and pushes it to the stack (as a frame) there it would be executed like a regular function. This is the reason asynchronous code is hard to debug, because those functions pushed to the stack are out of context when the time of execution comes, so for example the stack trace won’t help us too much (this is of course gets optimized with each version of JS released).

Resources

AJAX HTTP Requests Cancellation

AJAX HTTP Requests Cancellation

Sometimes when we call the server to perform some action as a response to an AJAX request, we want to discard this request because of particular reason. For example I had to perform a render action for a request with some parameters and send back as a response rendered template in HTML markup. This cancellation should help us dealing with unnecessary responses from server as well as avoiding redundant network traffic and unsynchronized UI when.

Scenario

Alice fills a form on the client side, for example name and phone and gets back from the server the fancy decorated rendered html to the browser.

Request:

// R1:

{
    "name": "A"
    "phone": ""
}

// R2:
{
    "name": "Al"
    "phone": ""
}

//...
//...
//...

// Ri:
{
    "name": "Alice Cooper"
    "phone": "+1 55"
}

//...
//...
//...

// Rn:
{
    "name": "Alice Cooper"
    "phone": "+1 555 651 55"
}

We obviously don’t want to create a request for each character filled in the form so we create some sort of a debounce function to help us reduce the HTTP requests. But we can do even more. Suppose that we have a debounce function of 2 seconds, and Alice filled her name in the name field, waited for 2 seconds that started to fill the phone field. Obviously a new request will be fired to the server while the older request is still live, but we don’t need the older one because it is now not synchronized with the UI. We need a way to cancel the old request and to treat only the latest request.

Naive Code And Example

here I created a little demo of the situation with the debounce function and a function to mock the AJAX task. Of course it is not the best code you will ever see and uses jQuery and blah blah but that clears the point. If you notice and sharp enough you can make a render request and while the request is being processed you can create another request for render.

1

Abort To The Rescue

The JavaScript xhr function (which I believe is still being used by most of the libraries/frameworks, for example vueResource and the before parameter where you would cancel the xhr request) comes with an option to abort it self. The only addition to the code above is single condition which can help your application reduce requests even more (with the debounce function)

$(document).ready(function(){
  var currentRequest = null;
  var debounce = null;
  $('#name, #phone').keyup(function(){
    if(debounce) clearTimeout(debounce);
    // --- this is the addition
    if(currentRequest){
        currentRequest.abort();
    }
    // ------------------------
    debounce = setTimeout(function(){
      var name = $("#name").val();
      var phone = $("#phone").val();
      currentRequest = performRenderAjax(name, phone);
    }, 1000);
  });
});

function performRenderAjax(name, phone){
  return $.ajax({
     method: 'GET',
     data: {
         'name': name,
         'phone': phone
     },
     success: function(){
         $('.rendered').html('<div style="background: pink; color: blue;">' + name + '</div><div style="background: brown; color: green;">' + phone + '</div>');
     }
  })
}