Data Flow In React
Published: 2021-11-16 16:36:19

The understanding of how data flows in react is crucial to building a bug free app. As a self-taught developer, I many of the times wrote apps that broke or behave unexpectedly. Going through the code to find nothing wrong but the code is still breaking; until I had a thorough understanding of how data flows in react, I was able to write code that is bug free and should there be a bug, I'll hunt it down quickly. In this guide, I will be walking you through some common pitfalls in react and how I was able to navigate through them.

##1)Unidirectional Data flow
React sends data from top to bottom. Data flows from the state to the rendered component and the nested component should there be one. To understand this, consider this code

```javascript
import React, { useState, useEffect } from 'react';

const ScreenOne = () => {

    const [number, setNumber] = useState({current: 0});

    const { current } = number;


    const _onClick = () => {
         setNumber({current: number.current + 1})
         //THE CURRENT NUMBER LOGGED TO THE CONSOLE WILL 
         //BE A SNAPSHOT OF THE PREVIOUS STATE, NOT THE NEW 
         //VALUE UPDATED BY THE BUTTON

          console.log(current)
    }
    return (
        <div>
            The Current State is <span>{current}</span>
            <button onClick={_onClick}>INCREMENT</button>
        </div>
    )
}

export default ScreenOne
```

To make sure the current number rendered on the screen is the same as that logged on the console, we can achieve this either by using a `useEffect` hook or by getting the `snapShot` of the previous state and adding directly to it as shown in this code:

```javascript
//USING USEEFFECT HOOK
import React, { useState, useEffect } from 'react'

...
useEffect(() => {
        (() => {
            console.log(current)
        })()
    }, [current])

...

//ADDING DIRECTLY TO THE SNAPSHOT OF THE PREVIOUS STATE
 const _onClick = () => {
      
            setNumber(prevState => ({current: prevState.current + 1}))
    }
....

```

##2) Universal state update
There might be a better name to describe this but what is means is that, when a single source of truth like redux is integrated into a react app, when a `dispatch` function is fired, the state of the entire app get updated even if there is no change in the previous state compared to the current state. This behaviour can really affect performance and in some instances, break the app. To get a better understanding of this concept of universal state update, consider this code:

For this code snippet, [redux](https://github.com/reduxjs/redux), [react-redux](https://github.com/reduxjs/react-redux), [redux-logger](https://github.com/LogRocket/redux-logger) were installed.

*ScreenTwo.component.jsx*
```javascript
import React from 'react';
import { connect } from 'react-redux'
import { setNumber } from '../redux/screen.action';
import ScreenThree from './screen-three.component';


const ScreenTwo = ({currentNumber, number}) => {

    const _onClick = () => {
        number(currentNumber + 1)
    }

    return (
        <div>
            This is the data from screen one { currentNumber }
            <button onClick={_onClick}>INCREMENT FROM SCREEN TWO</button>
            <ScreenThree />
        </div>
    )
}

const mapDispatchToProps = dispatch => ({
    number: data => dispatch(setNumber(data))
})


const mapStateToProps = ( { number : { initial_number } } ) => ({
    currentNumber: initial_number
})

export default connect(mapStateToProps, mapDispatchToProps)(ScreenTwo)
```

*ScreenThree.component.jsx*
```javascript
import React from 'react';
import { connect } from 'react-redux'
import { setValue } from '../redux/screen-three.action';

const ScreenThree = ({val, setVal}) => {

    const _onClick = () => {
        setVal(val + 1)
    }

    return (
        <div>
            <div>The is data from Screen Three {val} </div>
            <button onClick={_onClick}>INCREMENT SCREEN THREE</button>
        </div> 
    )
}

const mapStateToProps = ({value: { initial_value}}) => {
    //THIS LOG TO THE CONSOLE IS FIRED ANYTIME THERE IS A STATE 
    // UPDATE
    console.log('State is Being Updated from Screen Three')
    return { val: initial_value }
}

const mapDispatchToProps = dispatch => ({
    setVal: value => dispatch(setValue(value))
})

export default connect(mapStateToProps, mapDispatchToProps)(ScreenThree)
```
Given we have installed a logging library in our app, we can view from our console `State is Being Updated from Screen Three` regardless of where state got updated.
This behaviour of the state always been updated can really slow down the app. To mitigate this, the state should be memoized. With `memoization`, only the component where state changed will get re-rendered. To memoize out react state, we use a library called [reselect](https://github.com/reduxjs/reselect).
This code snippet shows a simple reselect setup:

*screen-three-selector.js*
```javascript
import { createSelector } from 'reselect'


//THE SELECTOR TAKES THE ENTIRE STATE AND RETURNS JUST 
// FRACTION OF IT
const selectValue = state => state.value


//BASED ON THE STATED RETURNED FROM THE FUNCTION ABOVE
//WE CAN NOW RETURN A SPECIFIC STATE VALUE
export const selectInitialValue = createSelector(
    [selectValue],
    (value) => value.initial_value
)
```

*screen-two-selector.js*
```javascript
import { createSelector } from 'reselect';


const selectNumber = state => state.number;

export const selectInitialNumber = createSelector(
    [selectNumber],
    (number) => number.initial_number
)
```

In our ScreenThree.component.jsx, we add these new lines of imports:
```javascript
import { selectInitialValue } from '../redux/screen-three-selectors';
import { createStructuredSelector } from 'reselect';
```
In our mapStateToProps function, we change it such that our selector has access to the state object.
```javascript
const mapStateToProps = createStructuredSelector ({
    val: selectInitialValue
})
```
Also in our *ScreenTwo.component.jsx*, we follow the same procedure, import `createStructuredSelectors` and `selectInitialValues`, the selector for ScreenTwo.

With this setup in place, we can be sure that a state update in one of the state values will not cause a re-rendering of the entire app state.
For more detailed documentation on the usage of the reselect library, please visit the official documentation [reselect](https://github.com/reduxjs/reselect).

These are some of the few ways data flow in react can lead to a bad app performance.