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.