Tag Archives: pure function

Pure components in React

ref – https://medium.com/technofunnel/working-with-react-pure-components-166ded26ae48
https://en.wikipedia.org/wiki/Pure_function
https://stackoverflow.com/questions/52680508/can-pure-functions-be-asynchronous
demo

Pure Functions

First, let’s talk about pure functions.

The definition of Pure Function says that for specific input parameters, we always have a specific output. The output is solely dependent on Input parameters and no other external variable.

Wikipedia defines it as:

  • Its return value is the same for the same arguments. 1 to 1. For a particular input, you won’t get different outputs. No mutation of local static variables, non-local variables, mutable reference arguments or I/O streams
  • Its evaluation has no side effects (no mutation of local static variables, non-local variables, mutable reference arguments or I/O streams).

example:

It uses non-local variable initialValue. So it is impure.

The code specified above is another example of the impure function, where the function is modifying the global variable getInitialValue, which does not lie under the scope of this function. Modifying this variable results in the introduction of Impurity to the function, making it Impure.

The function given above defines the output on the basis of the input parameter only.
No outer variables is adding its impact to the output.
Also, we can see that the function does not modify any other variable that does not belong to this function. Hence it adheres to the concept of Pure Functions.

Browser optimizations via Pure Functions

Pure Functions have a huge performance benefit during execution on the Browser.

Picture a scenario where a specific Pure Function is getting called multiple times.
The Application calls for the same function multiple times with the same parameters — assume “add(10, 20)”.
After executing it multiple times, the Chrome V8 Engine tries to optimize the code further by storing the execution result of the following function call. On the next call to the same function, with the same parameter, instead of executing the function again, the cached result is returned. Hence enhancing the Application Performance.

Functions should not introduce side effects

If the application updates certain data that is observable outside the called function, it can be considered a side effect introduced by the function.

Here are a few scenarios:

  • Modifying any external variable or object property (DOM)
  • – self explanatory. You use or modify outside global variables such as the document object.

  • Logging data to the console
  • – Similar to DOM, it is using outside object (console). Also, it prints something onto the screen.

  • Writing Data to a file
  • – It changes data to a file, which is global.

  • Writing data to the network
  • – Modifies network resources, which is global.

  • Triggering any external process
  • Calling any other (impure) functions with side-effects
  • Making Asynchronous Data Calls
  • – asynchronous actions usually is impure.

    Most things that we use asynchronous functions for are inherently side-effect(ful): I/O, network stuff, timers. But even if we ignore those, promises alone rely on some kind of global state for their asynchrony: the event loop. This violates purity.

    Pure Components

    Pure Components in React are components which do not re-renders when the value of state and props has been updated with the same values.
    If the value of the previous state or props and the new state or props is the same, the component is not re-rendered. Pure Components restricts the re-rendering ensuring the higher performance of the Component.

    Features of React Pure Components

    • Prevents re-rendering of Component if props and state is the same
    • Takes care of “shouldComponentUpdate” implicitly
    • – It is the same as Component except that Pure Components take care of shouldComponentUpdate by itself, it does the shallow comparison on the state and props data. If the previous state and props data is the same as the next props or state, the component is not Re-rendered.

    • State and Props are Shallow Compared – standard arrays won’t work anymore as pushing a value results in the same array. What we need to do is use dot notation to create another array, then push the value
    • Pure Components are more performant in certain cases

    Similar to Pure Functions in JavaScript, a React component is considered a Pure Component if it renders the same output for the same state and props value. React provides the PureComponent base class for these class components. Class components that extend the React.PureComponent class are treated as pure components.

    Pure Components Restricts Re-rendering

    Let’s look at this Component where we extend from standard Component. It is a impure component because we did not extend from PureComponent.
    What makes it Impure?

    Notice we do setInterval where we do a setState every 1 second.

    When the state gets set, it changes, so our virtual DOM gets diff-ed. Once it diffs, it writes the changes to the real DOM. We do this every second. However, the UI never changes because nothing changes. We’re drawing the same thing over and over again. There is effectively no difference in the UI — the new values are unchanged. Re-rendering, in this case, is an overhead.

    In order to solve this problem, we introduce…

    Pure Components

    They compare the initial and final values for the state and props variables. If there is no difference between the two, they won’t trigger the re-rendering logic for the component.

    Each time the state or props are updated it compares the previous and next value — if the values are the same the Render function is not triggered. Performance is then improved by not calling “render” repeatedly.

    Props and State Changes are Shallow Compared

    In Pure Component, the changes in react “props” and “state” is Shallow Compared to know whether they have changed. If they have changed, it renders. If it doesn’t, it does not render.

    Before we proceed further, we need to understand the concept of Shallow Comparison in JavaScript. The values saved in the variable can be either a primitive or reference type.

    Example “var a = 10”, the value saved in the variable “a” is of primitive type.

    The data stored in Objects and Array can be referred to as Reference type data. Comparing Primitive Values is not a concern.

    Problems arise when we have reference values during the comparison.

    Because the comparison used is shallow (only compare values), then the == will return true. However, these are actually two different objects. So even though their value may the same, their address reference is different. They are two different objects.

    In this example, we’re only dealing with one object. We have two references pointing to it. Thus, value comparison between the two references will be the same.

    We can also use spread operator to create a new object, and then copy the values over.

    IN this example, we create a whole new object with reference cloneData pointing to it. We then copy all properties/values from userInfo into it.
    Thus in the end, we have two objects, with same properties and values. One has reference userInfo pointing to it. The other has reference cloneData pointing to it. cloneData == userInfo will return false because the references are pointing to different memory locations.

    This issue with Shallow Comparison

    Say we have a reference pointing to an object with an array.
    We then push 6 onto it. When the PureComponent does a comparison, it will see that the before state’s userArray (and after state’s userArray) are ‘==’ (value equal) because they are pointing to the same object.

    But its clear that they are not the same. Before state’s userArray is 1,2,3,4,5. After state’s userArray is 1,2,3,4,5,6.

    In the case when the props and state changes are made to primitive type variable,
    state and props changes to reference variable may lead to incorrect results and inconsistent rendering.

    The simple answer to resolving the shallow issue is to work with immutable data using dot operator

    In the example above, we can see that comparing reference variables can lead to a problem — only the address of the object are compared before and after the update. Since we’re comparing references, the address still remains the same and the Pure Component does not detect any changes and does not re-render. We can resolve this by creating a new instance of the state variable if it represents the reference type.

    we’re creating a new reference array using the spread operator. When the setState is called, the component looks for the reference of a previous array object and a new array object is created. The reference is different since this is a new instance of the array, so the object has a new address. Now the pure component will get to know that the data has been updated, the “render” life cycle will be invoked and the component will be re-rendered with correct values.

    Example

    React.memo() does the same as PureComponent but it does not check for changes in state, only in props. Hence, I will use React.memo in functional component here as an example.

    npx create-react-app my-app
    cd my-app
    npm start

    Then in /src, create MyPureComponent.js:

    Basically, we initialize an array with a, b, c. Every time we click, we add the next few letters d, e, f, g….etc. We do this by using number 100, incrementing it, and getting the ascii code for it. Then we append that letter onto the array.

    In index.js, we use our component.

    Run the app and start clicking the button.

    As you can see, after doing shallow comparison of the previous prop to current prop, it gets the same reference value of the object. Thus, it never renders.

    The fix here is to re-create the array and then do the push. That way, whenever you manipulate the array, you put the results onto a new array. Thus when the objects are compared, they are not the same, and thus triggers the render.

    The other thing you can do is to use React.memo’s second parameter with a areEqual function

    Let’s look at another example where we start off with NOT using a comparator. We are erroneously using two references to point to an array object. When we update this array, our sub component does not update because it does a shallow compare on the same array object.

    When we run it, we see that in the subcomponent, nothing gets re-render because its shallow comparison of prevProp and nextProp comes out to be true.

    We fix it by using […arr] so that it creates a whole new objectArray, then copying all the values over. Memo will shallowly compare against two different objects, which then will actually correctly re-render because it will return false due to the two array objects being different.

    Now as you add in additional letters, you’ll see that the sub component re-renders.

    Using Comparator Func

    The code stays the same. All we need to do is to make sure we stick a comparator function in our memo’s 2nd parameter.

    The handling of adding a letter stays the same.

    then create an areEqual comparator:

    We default it to return true because we don’t want it to re-render for now. We want to see the previous prop and next prop.

    Great. We see that there is a difference. This is because the previous array is [‘a’, ‘b’, ‘c’]. We setArr to a new Arr that is a totally different array object by using […arr].
    That way, we can see that both props are different.

    Now let’s implement areEqual. Because our previous and next array data are different, we can actually make some decisions. If they are of different length, we re-render. If they are of different characters, we re-render. Otherwise, we don’t render.

    Full Code

    Copy and paste into App.js