React.memo обеспечивает выполнение поверхностного сравнения, когда реквизиты входят в компонент, и пропускает рендеринг компонента, когда они равны.
Заданный дочерний компонент Ячейка: При применении к созданному компоненту функции во время рендеринга другого, родительского компонента, новый компонент Cell будет создаваться при каждом рендеринге. Этот новый компонент Cell всегда будет выполнять поверхностные сравнения на своих объектах, но он будет перерисовываться при каждом рендеринге своего родителя.
useCallback, однако, запоминает этот обратный вызов функции Cell, если его массив зависимостей не изменяется во время родителя. повторная визуализация. В одиночку компонент функции Cell, обернутый в useCallback, всегда будет перерисовываться при получении реквизита, что происходит при каждом рендере его родителя. Разница, однако, заключается в том, что все его поддерево перерисовывается, если сам компонент воссоздается, как в случае использования самого React.memo. родителя.
Как вы заметите, при попытке перетащить ячейку Memoized, не обернутую в useCallback, перетаскивание не происходит. Это связано с тем, что исходный элемент, который вы пытаетесь перетащить, воссоздается как новый экземпляр при повторном рендеринге родительского элемента. Эта концепция объясняется более подробно здесь
Пример
const { useCallback, useState, useRef } = React;
function App() {
const [state, setState] = useState(false);
const [title, setTitle] = useState("");
const Cell = useCallback(({ title }) => {
console.log(`${title} rendering`);
function onDragStart() {
setState(true);
}
function onDragEnd() {
setState(false);
}
return (
<div draggable onDragStart={onDragStart} onDragEnd={onDragEnd}>
Drag {title}
</div>
);
}, []);
const MemoizedCell = React.memo(({ title }) => {
console.log(`${title} rendering`);
function onDragStart() {
setState(true);
}
function onDragEnd() {
setState(false);
}
return (
<div draggable onDragStart={onDragStart} onDragEnd={onDragEnd}>
Drag {title}
</div>
);
});
const MemoizedCallbackCell = useCallback(
React.memo(({ title }) => {
console.log(`${title} rendering`);
function onDragStart() {
setState(true);
}
function onDragEnd() {
setState(false);
}
return (
<div draggable onDragStart={onDragStart} onDragEnd={onDragEnd}>
Drag {title}
<button onClick={() => setTitle(" Updated")}>Change Title</button>
</div>
);
}),
[]
);
return (
<div className="App">
<Cell title="Cell" />
<MemoizedCell title="Memoized Cell" />
<MemoizedCallbackCell title={"Memoized Callback Cell" + title} />
Is dragging {`${state}`}
<br />
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));