Categories
React Tips

React Tips — Data Flow and Pure Components

Spread the love

React is the most-used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at how to share data between components and speed up rendering with pure components.

Data Flow with Flux

Flux architecture is a way to create a data layer in JavaScript apps. It works by adding the data layer in a centralized data store. Updates to the store are done by dispatching actions to the store which updates the store’s state.

Any component that needs the data can subscribe to the latest updates to the data store to get the relevant state.

This is a good way to organize our data layer structure because it removes the need to share data between components directly. All data is in one place.

This reduces the confusion that arises from sharing data between components, especially if we need to pass data between unrelated components by passing data between a chain of related components.

The most common library for implementing the Flux architecture is with Redux. We can use it by writing the following code:

index.js :

import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import App from "./App";
import { Provider } from "react-redux";

const counter = (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    default:
      return state;
  }
};

const store = createStore(counter);

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  rootElement
);

App.js :

import React from "react";
import { useSelector, useDispatch } from "react-redux";

export default function App() {
  const count = useSelector(state => state);
  const dispatch = useDispatch();

  return (
    <>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
      <p>{count}</p>
    </>
  );
}

In the code above, we used the React hooks version of the React-Redux API. First, we created the store with:

const counter = (state = 0, action) => {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    default:
      return state;
  }
};

const store = createStore(counter);

Then we wrap the Provider component around the entry point of our app in index.js . We pass in the store object so that we can access it.

The store is created by first creating the counter reducer, which updates the state . Then we pass in the counter reducer to createStore to create the store.

Then in App , we access the store by using the useDispatch hook so that we can dispatch actions with the returned function. Then we use the useSelector hook to return the state from our store with the callback.

Once we did that, we call dispatch when we click the Increment button. In the dispatch function call, we pass in the type property with the 'INCREMENT' action, which means that the 'INCREMENT' action in the counter reducer will be completed.

Then when we click the Increment, count will update because we updated the store with state + 1 each time the 'INCREMENT' action is dispatched.

Pure Components

Pure components are React components that implement the shouldComponentUpdate method.

The ones that implement shouldComponentUpdate are always class-based components. We can also create components that don’t implement that by returning the result that is derived from the props that are passed in.

In general, a component is pure if the return value of the component is only determined by its input values.

We can create a classed based component and use it as follows:

import React from "react";

class Pecentage extends React.PureComponent {
  render() {
    const { score, total } = this.props;
    return (
      <div>
        <span>{Math.round((score / total) * 100)}%</span>
      </div>
    );
  }
}

export default function App() {
  return <Pecentage score={70} total={100} />;
}

In the code above, we have the Percentage component, which implements React.PureComponent .

It takes 2 props, score and total and we return the percentage point derived from score divided by total .

shouldComponentUpdate is automatically included and it does a shallow comparison of the data, so we don’t need to write one ourselves to do the comparison since both props are numbers. Therefore, React will rerender the component only if the props change in value.

On the other hand, if the props are objects, then we’ll need to implement the method and do the checks ourselves.

It returns the same output given the same input, so it’s a pure component.

Also, we can implement pure function components as follows:

import React from "react";

const Pecentage = ({ score, total }) => {
  return (
    <div>
      <span>{Math.round((score / total) * 100)}%</span>
    </div>
  );
};

We just pass in the props as we need to and it also returns the same output given the same input, so it’s a pure component.

Conclusion

If our apps have multiple components that need to share data, then we need Flux architecture. To implement it, the best way is to use popular existing libraries like Redux.

The pure component has optimizations that are done by React to speed up rendering. They only render if the props change. The change detection is done by shallow comparison.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *