Самаранокӣ: memo, useMemo, useCallback
Аввал — аз кашиданҳо натарсед
Шумо аллакай медонед, ки компонент ҳангоми тағйири ҳолат ва ҳангоми кашидани волид аз нав кашида мешавад. Навомӯзон аксар вақт метарсанд: «ҳама чиз аз ҳар атса аз нав кашида мешавад!». Аммо кашидан — даъвати функсия ва муқоисаи объектҳост, одатан ҳиссаҳои миллисония. DOM-и ҳақиқӣ танҳо дар ҷое иваз мешавад, ки фарқ ҳаст. Дар аксари барномаҳо ҳеҷ чизро оптимизатсия кардан лозим нест.
Оптимизатсия вақте лозим аст, ки мушкили намоён ҳаст: майдони воридкунӣ «суст мешавад», рӯйхати ҳазорон сатр пурра аз
нав кашида мешавад, дар ягон ҷо ҳисоби вазнин меравад. Он гоҳ React се асбоб дорад: useMemo, memo ва useCallback.
Онҳоро ҳатман фаҳмидан лозим аст — онҳо дар ҳар лоиҳаи воқеӣ вомехӯранд — ва бо ақл истифода бурдан.
useMemo: натиҷаи ҳисобро дар хотир нигоҳ доштан
const { useMemo } = React;
function ProductList({ products, query }) {
const [dark, setDark] = useState(false);
const visible = useMemo(
() => products.filter((p) => p.title.toLowerCase().includes(query.toLowerCase())),
[products, query],
);
return (
<div className={dark ? "dark" : ""}>
<button onClick={() => setDark(!dark)}>Мавзӯъ</button>
<ul>{visible.map((p) => <li key={p.id}>{p.title}</li>)}</ul>
</div>
);
}
useMemo(функсия, [вобастагиҳо])функсияро ҳангоми кашидани аввал даъват мекунад ва натиҷаро дар хотир нигоҳ медорад.- Ҳангоми кашиданҳои навбатӣ, агар вобастагиҳо тағйир наёфта бошанд, фавран қимати дар хотирбударо бармегардонад, бе даъвати функсия.
- Иваз кардани мавзӯъ дигар рӯйхатро аз нав филтр намекунад:
productsваqueryҳамонанд.
Барои филтри сад мол ин лозим нест — вай худ аз худ зуд аст. useMemo вақте лозим аст, ки ҳисоб воқеан вазнин аст
(ҳазорон унсур, математикаи мураккаб) ё вақте нигоҳ доштани ҳамон истинод ба объект муҳим аст (дар ин бора дар поён).
memo: кашидани компонентро гузарондан
memo компонентро мепечонад ва ба React мегӯяд: «агар props ҳамон бошанд, ки дафъаи гузашта, маро даъват накун — натиҷаи
пешинаро истифода бар»:
const { memo } = React;
const UserCard = memo(function UserCard({ name, avatar }) {
console.log("render", name);
return (
<div className="card">
<img src={avatar} alt="" />
<p>{name}</p>
</div>
);
});
Акнун ҳангоми кашидани волид UserCard танҳо вақте аз нав кашида мешавад, ки name ё avatar тағйир ёфт. Тағйироти
ҳолат ва контексти худаш компонентро мисли одатӣ аз нав мекашанд — memo танҳо ба props нигоҳ мекунад.
Дом: муқоиса аз рӯи истинод
memo ҳар prop-ро тавассути Object.is муқоиса мекунад — барои объектҳо, массивҳо ва функсияҳо ин муқоисаи
истинодҳо аст. Дар бадани компонент бошад, ҳангоми ҳар кашидан объектҳо ва функсияҳои нав сохта мешаванд:
function Parent() {
const [n, setN] = useState(0);
const style = { color: "red" }; // ҳар дафъа объекти нав
const handleClick = () => console.log(1); // ҳар дафъа функсияи нав
return (
<>
<button onClick={() => setN(n + 1)}>{n}</button>
<Child style={style} onClick={handleClick} /> {/* memo кӯмак намекунад! */}
</>
);
}
Барои memo ин ҳар дафъа «props-и нав» аст, ва Child ба ҳар ҳол аз нав кашида мешавад. Барои он ки memo кор кунад,
объектҳо ва функсияҳо дар props бояд истинодро байни кашиданҳо нигоҳ доранд:
- доимиҳо — берун аз компонент баровардан;
- объектҳо ва массивҳои ҳисобшаванда —
useMemo; - функсияҳо —
useCallback.
useCallback: функсияи устувор
const { useCallback } = React;
function TodoList() {
const [todos, setTodos] = useState([]);
const handleDelete = useCallback((id) => {
setTodos((list) => list.filter((t) => t.id !== id));
}, []);
return todos.map((t) => <TodoItem key={t.id} todo={t} onDelete={handleDelete} />);
}
const TodoItem = memo(function TodoItem({ todo, onDelete }) {
return <li onClick={() => onDelete(todo.id)}>{todo.text}</li>;
});
useCallback(функсия, [вобастагиҳо]) ҳамон як функсияро бармегардонад, то вобастагиҳо тағйир наёфтаанд. Дар асл ин
useMemo(() => функсия, вобастагиҳо) аст.
Ба setTodos((list) => …) диққат диҳед. Агар дар дохил todos.filter(…) мебуд, todos-ро ба вобастагиҳо илова кардан
лозим меомад — ва функсия ҳангоми ҳар тағйири рӯйхат иваз мешуд. Функсияи навсозӣ рӯйхати навро аз аргумент мегирад, барои
ҳамин вобастагӣ нест ва функсия то абад устувор аст.
Чӣ тавр ёфтан, ки чӣ суст мекунад
Тахмин накунед — чен кунед:
- React Developer Tools (васеъкунандаи браузер) → ҷадвалаки Profiler: амалро сабт мекунед ва мебинед, ки кадом компонентҳо аз нав кашида шуданд ва ин чӣ қадар вақт гирифт;
- дар танзимоти ҳамон ҷо — «Highlight updates»: компонентҳои аз нав кашидашуда дар саҳифа равшан мешаванд;
console.logдар бадани компонент — соддатарин ҳисобкунаки кашиданҳо.
Сабабҳои воқеии маъмули кори суст: рӯйхатҳои хеле дароз (ҳал — танҳо қисми намоёнро нишон додан, «виртуализатсия»), ҳисобҳои вазнин ҳангоми ҳар кашидан, ҳолат дар дарахт аз ҳад баланд (майдони воридкунӣ дар решаи барнома тамоми барномаро аз нав мекашад — ҳолатро поёнтар, ба ҷое, ки лозим аст, фуроред).
Кай оптимизатсия НАКУНЕД
useMemoваuseCallbackхудашон вақт ва хотира мегиранд ва кодро мураккаб мекунанд. Ҳама чизро ба онҳо печондан зарар аст.useCallbackбеmemoдар компоненти кӯдак қариб бефоида аст: агар кӯдак мемоизатсия нашуда бошад, ба ҳар ҳол аз нав кашида мешавад.- Аввал — сохтори дуруст: ҳолат ҳарчи поёнтар, ҳисобҳо ҳангоми кашидан, бе эффектҳои зиёдатӣ. Ин аксари мушкилотро бе
ягон
memoҳал мекунад.
Дар версияҳои нави React React Compiler пайдо мешавад, ки чунин мемоизатсияро худкор мегузорад. Вале фаҳмидани он ки вай чӣ мекунад ва чаро, ба ҳар ҳол лозим аст.
Хулоса
- Кашидан одатан арзон аст. Вақте мушкили ченкардашуда ҳаст, оптимизатсия кунед.
useMemo(() => ҳисоб, [deps])— натиҷаи ҳисоби вазнин ё объектро дар хотир нигоҳ доштан.memo(Компонент)— ҳангоми ҳамон props кашиданро гузарондан.- Props аз рӯи истинод муқоиса мешаванд: объектҳо ва функсияҳои нав
memo-ро мешикананд. useCallback(fn, [deps])— ҳамон функсия байни кашиданҳо; якҷоя боsetX((old) => …)— бе вобастагиҳои зиёдатӣ.- Бо React DevTools Profiler чен кунед.