Представьте компонент, который показывает информацию о текущем пользователе и статус активен ли пользователь в данный момент. Пример такого компонента:
import { useState, useEffect } from "react";
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`https://api.example.com/users/${userId}`)
.then(response => response.json())
.then(data => {
const isActive = data.accountStatus === "active" &&
new Date(data.lastLogin) >= new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
setUser({
name: `${data.firstName} ${data.lastName}`,
email: data.email,
isActive,
});
});
}, [userId]);
if (!user) {
return <p>Loading...</p>;
}
return (
<div>
{user.name} is {user.isActive ? "active" : "inactive"}
</div>
);
}
Это довольно распространенный пример компонента на React. Он не сложный, но в нем есть одна проблема: смешение разных уровней абстракций.
Когда вы пишите код, то смешение разных уровней абстракций в пределах одной функции часто приводит к путанице и затрудняет понимание. Более чистый подход заключается в том, чтобы поддерживать каждую функцию на своем уровне абстракции. На практике это означает, что более высокие функции не должны погружаться в детали, а должны использовать более мелкие функции, в которых скрыты детали.
Рассмотрим тот же компонент после рефакторинга:
import { useState, useEffect } from "react";
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then((data) => setUser(normalizeUser(data)));
}, [userId]);
if (!user) {
return <Loader />;
}
return <UserStatus user={user} />;
}
Обратите внимание, насколько легче стало его читать. Достаточно одного взгляда, чтобы разобраться что компонент делает.
https://www.tymzap.com/blog/the-magic-of-keeping-one-abstraction-level-per-function