Here is a small article highlighting the steps of separating business logic from UI in React, using the code you provided as an example:
Steps to separate business logic from UI in React:
Identify the business logic in your components. This includes any code that deals with data fetching, data manipulation, or state management.
Extract the business logic into separate files or modules. This will make your code more organized and reusable.
Use custom hooks to encapsulate the business logic and make it available to your components. Custom hooks are a great way to share state and functionality between components without having to pass props around.
Update your components to use the custom hooks instead of the business logic code directly. This will make your components more concise and easier to understand.
Example: (code start where View shouldn't care About how to get an item or how to calculate the price )
// Before
const ItemPage = ({ itemId }) => {
const [item, setItem] = useState(null);
useEffect(() => {
const fetchItem = async () => {
const response = await fetch(`https://api.example.com/items/${itemId}`);
const data = await response.json();
setItem(data);
};
fetchItem();
}, [itemId]);
const onSubmit = () => {
// Your submit logic here
};
return (
<div>
<Name>{item.name}</Name>
<Price>{item.discountPrice || item.price}</Price>
<Button onClick={onSubmit}>Add to cart</Button>
</div>
);
};
Step 1: Identify Business Logic
Before diving into the code, it's essential to identify the areas of your components where business logic resides. This typically includes tasks like data fetching, data manipulation, and state management.
Step 2: Initial Abstraction from UI
In this step, we'll create an initial abstraction from the UI by moving the data fetching logic into a separate function. This keeps our component clean and focused on rendering.
const Item = ({ itemId }) => {
const [item, setItem] = useState(null);
useEffect(() => {
const fetchItem = async () => {
const response = await fetch(`https://api.example.com/items/${itemId}`);
const data = await response.json();
setItem(data);
};
fetchItem();
}, [itemId]);
return { item };
};
Step 3: Further Abstraction with Custom Hooks
To improve code reusability, we can create custom hooks to encapsulate our business logic. This makes it easy to share state and functionality across components.
Creat api/item.js :
// api/item.js
const getItemById = async (id) => {
const response = await fetch(`https://api.example.com/items/${id}`);
const item = await response.json();
return item;
};
export { getItemById };
creat a Custom Hook (useItem hook ):
// useItem hook
const useItem = ({ itemId }) => {
const [item, setItem] = useState(null);
useEffect(() => {
const fetchItem = async () => {
const response = await itemsApi.getItemById(itemId);
setItem(response);
};
fetchItem();
}, [itemId]);
return { item };
};
Step 4: Helper Functions
In some cases, it's beneficial to create helper functions to handle specific tasks, such as parsing item data.
// helpers/item.js
const parseItem = (item) => {
return {
name: item.name,
finalPrice: item.discountPrice || item.price,
};
};
Step 5: Final Component
Now, with our business logic abstracted away, our final component becomes cleaner and easier to understand:
const ItemPage = ({ itemId }) => {
const { item } = useItem({ itemId });
const formattedItem = parseItem(item);
const onSubmit = () => {
// Your submit logic here
};
return (
<div>
<Name>{formattedItem.name}</Name>
<Price>{formattedItem.finalPrice}</Price>
<Button onClick={onSubmit}>Add to cart</Button>
</div>
);
};
Conclusion :
Benefits of separating business logic from UI:
Code reusability: When business logic is isolated, it becomes easier to reuse components across different parts of the application or even in other projects.
Testability: Because logic is separate from presentation, writing unit tests for your business logic is easier.
Maintainability: Separating business logic from UI makes your code more maintainable and easier to update. This is because you can focus on changing the business logic without having to worry about the UI.
I hope this article has been helpful!