Мне нужно сделать демонстрацию использования React Hooks useMemo. У меня есть рабочий код, который делает то, что я хочу:
const SpeakerCardDetail = React.memo(
({id,...
Я нашел связь, который показывает, что я мог бы использовать синтаксис, похожий на этот, но я не могу точно понять это.
Это насколько я понял:
const SpeakerDetail = React.useMemo(() => {
({ id,
Хотя явно не то. Я понимаю, что React.memo решает проблему, но мне нужно показать useMemo в действии, и я надеюсь, что есть альтернативный синтаксис, который я могу использовать.
React.memo позволяет функциональному компоненту иметь ту же оптимизацию, что и PureComponent для компонентов на основе классов. useMemo предназначен для запоминания вызовов функций внутри функционального компонента. Заменить один на другой будет сложно, так как у них разное назначение.
Я надеюсь, что смогу получить тот же результат, что и React.memo, то есть возврат чистой функции сохраняется с мемоизацией.





React.memo и React.useMemo вообще не эквивалентны (не полагайтесь на сходство имен). Вот цитата из React.memoдокумент:
React.memois a higher order component.
Таким образом, это HOC, который может оптимизировать воспроизведение вашего компонента, учитывая, что он отображает тот же результат с теми же свойствами.
React.useMemo, с другой стороны, более общий и возвращает запомненное значение:
Pass a “create” function and an array of dependencies.
useMemowill only recompute the memoized value when one of the dependencies (eitheraorb) has changed.
const memoizedValue = useMemo(
() => computeExpensiveValue(a, b),
[a, b]
);
И хотя его можно взломать, чтобы использовать вместо React.memo, это не его цель, и это больше добавит путаницы, чем поможет. useMemo является хуком и подпадает под действие определенные правила использования.
И есть еще такое предупреждение:
In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without
useMemo— and then add it to optimize performance.
Спасибо. Я пришел к такому же выводу и был обманут именованием. Сейчас я использую в качестве примера результаты сортировки перед рендерингом.
Хотя, должен сказать, я долго смотрел на этот пример, потому что он заставляет их чувствовать себя примерно одинаково. codeandbox.io/s/7m03xn9wlx
Хотя memo — HOC, а useMemo — хук, вы можете использовать их для достижения того же результата.
Для контекста, HOC — это более старый шаблон React, который много лет использовался как с классовыми, так и с функциональными компонентами. Вы все еще можете использовать его сегодня (плана прекращения поддержки нет).
Хуки — это относительно новая концепция (около года), которая расширяет функциональные компоненты и во многих случаях резко упрощает код. Вот почему многие разработчики переходят на использование хуков.
В любом случае, и memo, и useMemo принимают два аргумента: функцию и реквизит. Если ни один из реквизитов не изменится при последующих повторных рендерингах, функция не будет выполняться снова, а вместо этого вернет предыдущий результат. Фактически это заменяет обратные вызовы shouldComponentUpdate чисто функциональным подходом.
С memo ваш код будет выглядеть так:
const SpeakerCardDetail = React.memo(
(props) => <div>{props.name}</div>
)
С useMemo вы бы написали:
const SpeakerCardDetail = (props) => useMemo(() => <div>{props.name}</div>)
Обратите внимание, что useMemo используется внутри функции вашего компонента, а memo оборачивает функцию.
Традиционно useMemo можно записать так:
function SpeakerCardDetail(props) {
return useMemo(
() => <div>{props.name}</div>
)
}
Теперь приведенный выше код будет перерисовываться каждый раз, что делает функцию useMemo немного бесполезной. Чтобы заставить его работать, нам нужно добавить второй аргумент. (memo по-прежнему работает даже без указания второго аргумента, но вы можете добавить его, чтобы настроить)
Есть небольшая разница в формате второго аргумента. memo ожидает функцию, которая сравнивает предыдущие и текущие реквизиты, точно так же, как shouldComponentUpdate делает это для компонентов класса.
const SpeakerCardDetail = React.memo(
(props) => <div>{props.name}</div>
,
// return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false
(prevProps, nextProps) => prevProps.name === nextProps.name
)
useMemo, с другой стороны, ожидает массив в качестве второго аргумента. Всякий раз, когда значения в массиве изменяются, функция будет выполняться снова.
function SpeakerCardDetail(props) {
return useMemo(
() => <div>{props.name}</div>
,
[props.name]
)
}
Там действительно нет больше магии, чем это. И memo, и useMemo используются для запоминания результата функции, единственная разница в том, что memo — это HOC (и может использоваться для переноса как классов, так и функциональных компонентов), а useMemo — хук (и может использоваться только внутри функциональных компонентов). .
Не могли бы вы предложить нам, что лучше, чтобы мы могли использовать оба подхода?
@Muhammad Ни один из них строго не лучше другого. Если вы используете компоненты класса, вы должны использовать memo. Если вы используете функциональные компоненты с хуками, вы можете использовать useMemo (хотя в этом случае вы также можете использовать memo). useMemo также имеет более краткий второй аргумент. В конце концов, это всего лишь вопрос предпочтений. Любая разница в производительности должна быть незначительной.
Когда компонент находится внутри условия, с useMemo вы получаете меньше хуков, чем ожидалось, поэтому в этом случае я полагаю, что memo — единственный вариант.
Суть в том, что если вам удобно использовать хуки и вы используете их в своем проекте, вы можете предпочесть useMemo для «согласованности». Хотя, как отмечает @GoranJakovljevic, применяются обычные правила хуков, поэтому вы всегда можете вернуться к React.memo. Если вы не используете хуки, всегда используйте React.memo.
Подводя итог React.memo против useMemo / TLDR:
React.memo — это компонент более высокого порядка (HOC для краткости), который запоминает компонент реакции на основе свойств.
export function SomeComponent({ num }) {
return <p>{num * 10}</p>
}
export default React.memo(SomeComponent, function areEqual(
prevProps,
nextProps
) {
if (prevProps.num !== nextProps.num) {
return false
}
return true
})
useMemo — это хук реакции, который запоминает значение, возвращаемое функцией, которую вы ему предоставляете.
export function SomeComponent({ num }) {
const res = useMemo(() => num * 10, [num])
return <p>{res}</p>
}
Использование React.memo заставит React пропустить рендеринг компонента, если его свойства не изменились.
Пример:
const Child = React.memo(props => {
console.info("rendered");
return <React.Fragment>{props.name}</React.Fragment>;
});
class App extends React.Component {
state = {
value: 1,
name: "Jioke"
};
handleClick = () => {
this.setState({
value: this.state.value + 1
});
};
render() {
return (
<React.Fragment>
<Child name = {this.state.name} />
<div>{this.state.value}</div>
<button onClick = {this.handleClick}>+</button>
</React.Fragment>
);
}
}
Когда мы нажимаем кнопку, Child Компонент не перерисовывается (rendered отображается только 1)
Примечания: Чем больше реквизитов, тем больше вычислений, сравнения (проверка рендеринга или нет) добавленная стоимость сравнения не стоит того для «простого» компонента с точки зрения затрат рендеринга, согласования, изменения DOM и побочных эффектов. Так что будьте осторожны, чтобы решить, использовать его или нет
useMemo будет кэшировать значение, чтобы его не нужно было пересчитывать каждый раз при повторном рендеринге компонентов. Он сохраняет возвращаемое значение функции и возвращается, если входные данные не изменились.
Пример:
import { useState, useMemo } from "react";
import ReactDOM from "react-dom";
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const calculation = useMemo(() => expensiveCalculation(count), [count]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};
return (
<div>
<div>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key = {index}>{todo}</p>;
})}
<button onClick = {addTodo}>Add Todo</button>
</div>
<hr />
<div>
Count: {count}
<button onClick = {increment}>+</button>
<h2>Expensive Calculation</h2>
{calculation}
</div>
</div>
);
};
const expensiveCalculation = (num) => {
console.info("Calculating...");
for (let i = 0; i < 1000000000; i++) {
num += 1;
}
return num;
};
ReactDOM.render(<App />, document.getElementById('root'));
у нас есть дорогая функция, которая запускается при каждом рендере.
При изменении счетчика или добавлении задачи вы заметите задержку в выполнении.
Поэтому, когда мы используем useMemo, дорогая функция будет работать только тогда, когда ее зависимости изменились.
В следующем примере дорогостоящая функция будет выполняться только при изменении счетчика, а не при добавлении задач.
Подожди, что тебе нужно сделать? просто любой пример использования
useMemo?