React Separation of Concern: separation of UI and business logic
When you’re building a React application, Often you’ll find yourself in a situation where you need to separate the UI and business logic. In this article, I will show you how to do that. This blog is mostly inspired from one of my answer on stack overflow.
To explain this, I'll use a simple example of counter
. We have a Counter
component which has a button to increment and decrement the counter. The Counter
component is responsible for rendering the UI, handling the click events and updating the counter value. This is the UI and business logic both in one component.
Traditional way
import { useState } from "react";
import numberWithCommas from "./helper";
const Counter = () => {
const [count, setCount] = useState(9999);
const increaseCount = () => setCount(count + 1);
const decreaseCount = () => setCount(count - 1);
return (
<div>
<p>{numberWithCommas(count)}</p>
<div>
<button onClick={increaseCount}>Increase</button>
<button onClick={decreaseCount}>Decrease</button>
</div>
</div>
);
};
The numberWithCommas
function is a helper function which adds commas to the number. This is a pure function which takes a number and returns a string.
const numberWithCommas = (x) => {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};
Current Example
Separation of Concern
Using, Separation of Concern, we can separate the UI and business logic. We can create a Counter
component which is responsible for rendering the UI and a useCounter
hook which is responsible for updating the counter value. The Counter
component will use the useCounter
hook to get the counter value and the functions to update the counter value.
Counter Component
The component should only be responsible for rendering the UI. It should not be responsible for updating the counter value.
import useCounter from "./useCounter";
const Counter = () => {
const { count, increaseCount, decreaseCount } = useCounter();
return (
<div>
<p>{count}</p>
<div>
<button onClick={increaseCount}>Increase</button>
<button onClick={decreaseCount}>Decrease</button>
</div>
</div>
);
};
useCounter Hook
The hook should only be responsible for handling all the business logic.
import { useState } from "react";
import numberWithCommas from "./helper";
const useCounter = () => {
const [count, setCount] = useState(9999);
const increaseCount = () => setCount(count + 1);
const decreaseCount = () => setCount(count - 1);
return {
count: numberWithCommas(count),
increaseCount,
decreaseCount
};
};
Example with separation of concern
Conclusion
This approach should segregate the view and business logic. This will make the code more readable and maintainable.