How to Refactor Complex React Pages with Component‑Based Design
This article explains how to tackle hard‑to‑maintain React pages by applying design patterns, splitting horizontal business logic into basic and block components, and using component composition to dramatically reduce code size while improving readability and maintainability.
Background
In everyday development, encountering pages that are extremely hard to maintain is common, and many developers feel frustrated. The author shares experiences from business development to inspire readers.
As requirements iterate, the page code grows to thousands of lines with deep HTML nesting and tangled React hooks (useEffect, useState, useRef), making modifications painful. A decision was made to refactor.
How to Refactor Complex Pages
The author, primarily a backend developer, suggests three levels of refactoring based on the source of complexity:
If a single business concept leads to many nested if‑else statements, apply the Strategy Pattern .
If multiple business concepts intertwine, use the Chain of Responsibility Pattern to organize layers.
For higher‑level abstractions such as different business roles requiring distinct execution paths, adopt the Template Method Pattern to define default logic and allow selective overrides.
While backend complexity often stems from vertical depth, frontend complexity usually comes from horizontal accumulation of many UI blocks (detail sections, forms, tabs, etc.). The solution is to use a compositional mindset to split these horizontal blocks, which in React translates to breaking down business logic into reusable components.
Componentization
A React application can be visualized as a component tree. The author classifies components into two categories:
Basic components : Small, reusable units with weak business semantics, emphasizing generality.
Block components : Large components that encapsulate heavy business knowledge, with low reusability but high cohesion.
Below is an illustration of the component tree (image omitted).
Basic Component Example: AliTalk IM
The component receives a user ID, renders an IM widget, and handles chat window lifecycle internally. Core code:
type ChatProps = { uid?: string; };
const Chat: FC<ChatProps> = (data) => {
const [showChat, setShowChat] = useState(true);
useEffect(() => {
console.log('init Alitalk: ' + data.uid);
return () => {
console.log('destroy Alitalk: ' + data.uid);
setShowChat(false);
const boxes = document.getElementsByClassName('weblite-iframe');
for (let i = 0; i < boxes.length; i++) {
boxes[i].remove();
}
};
}, []);
return (
<div>{showChat && (<Alitalk uid={data.uid} pid={'xx'} bizType={1} bizId={'xx'}>
<img width={24} height={24} src="https://img.alicdn.com/imgextra/i2/O1CN01acXzMG1d5JsurHGVR_!!6000000003684-2-tps-200-200.png" />
<span style={{marginLeft: '5px', color: '#FF6600'}}>chat now</span>
</Alitalk>)}</div>
);
};
export default Chat;Usage is as simple as <Chat uid={detailData?.data?.buyerAliTalkId} />.
Block Component Example: Action‑Point Modal
For a transfer service order, clicking a button opens a modal form. After submission, the request is sent and the modal closes automatically. The component encapsulates all related business logic.
Component usage (simplified):
<Fragment>
<Button.Group>
<EstimatedQuotationModalForm orderId={detailData?.id} />
<DomesticWarehouseReceivingModalForm orderId={detailData?.id} />
<OfficialQuotationModalForm orderId={detailData?.id} />
<MarkOrderPaidModalForm orderId={detailData?.id} />
<MarkOrderExceptionModalForm orderId={detailData?.id} />
<MarkOrderClosedModalForm orderId={detailData?.id} />
<TransferOrderModalForm orderId={detailData?.id} />
</Button.Group>
</Fragment>After componentizing, the main page shrank from several thousand lines to about 200 lines, containing only component imports and layout composition. Each block component focuses on its own business abstraction, adhering to the SLAP (Single Level of Abstraction Principle).
Thoughts on Component Design
Basic components should be atomic, with generic props to maximize reuse (e.g., chat, user info, auth). Block components, on the other hand, need not be reusable; their goal is to isolate business layers, achieving high cohesion and readability. Design block components with a coarse granularity first, then refine as business evolves.
Although frontend component design and backend class design appear different, they share the same underlying philosophy: use pure functions, avoid mutable shared state, and separate concerns across layers. This aligns with the SLAP principle, which applies equally to UI components and backend classes.
As Paul Graham wrote in "Hackers & Painters", the creative process never truly ends—just like a painting, a well‑designed system evolves continuously.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
