Введение
Мемоизация — это интересная концепция, и я считаю, что все разработчики Javascript должны быть увлечены и знакомы с ней.
Я буду рассматривать эту тему следующим образом: ЧТО, ПОЧЕМУ и КАК
1. Что такое мемоизация?
Когда я впервые увидел слово мемоизация, мне на ум пришло слово запоминать, и я был в замешательстве! Как JavaScript должен запоминать и помнить что-то от моего имени (я подумал, есть ли какая-то форма машинного обучения в JavaScript по умолчанию), но углубившись в концепцию мемоизации, я понял, что это все о помощи JavaScript в запоминании предыдущих вычислений.
Говоря простыми словами, мемоизация — это техника оптимизации, которая помогает ускорить повторяющиеся, дорогостоящие вычисления путем запоминания результата предыдущего вычисления.
2. Зачем нужна мемоизация?
Эта техника направлена на то, чтобы сделать вычисления эффективнее и быстрее; если выполняется дорогостоящее вычисление, то при мемоизации результат может быть сохранен в кэше и извлечен, когда это необходимо, поэтому нет необходимости в повторном вычислении.
Все это есть при мемоизации, и в дополнение к этому вы получаете эффективные вычисления, оптимизацию и ускорение вычислений (так как пропускается то, что было сделано ранее).
3. Как реализовать мемоизацию?
В JavaScript?
Реализация мемоизации заключается в передаче функции в мемоизированный обратный вызов
const multiplyBy10 = (num: number) => num * 10;
console.log('Simple call', multiplyBy10(3));
/**
*
* Explanation: a simple memoize function that takes in a function
*
* @param fn a function to be memoized or used to perform computation
* @returns a memoized function
*/
const memoize = (fn: Function) => {
let cache = {};
return (...args) => {
let num = args[0]; // just taking one argument here
if (num in cache) {
console.log('Fetching from cache');
return cache[num];
} else {
console.log('Calculating result');
let result = fn(num);
cache[num] = result;
return result;
}
}
}
// creating a memoized function for the 'multiplyBy10' pure function
const memoizedAdd = memoize(multiplyBy10);
console.log(memoizedAdd(3)); // calculated
console.log(memoizedAdd(3)); // cached
console.log(memoizedAdd(4)); // calculated
console.log(memoizedAdd(4)); // cached
спасибо Codegrepper & Agreeable Armadillo за ссылку на код
В React
Существует несколько способов реализации мемоизации, и они основаны на том, что необходимо сделать
- для компонента используйте React.memo()
- Если вы хотите мемоизировать функцию, то используйте React.useCallback();
- Если вы хотите запомнить результат дорогой функции, то используйте React.useMemo();
Эти методы предотвращают ненужный повторный рендеринг в react, если использовать их правильно.
Понимание React.memo()
/**
* Explanation:
* this function accept a name and render a styled version of it
*
* @param name
* @returns JSX.Element (styled version of the name)
**/
import React from 'react';
function RenderName({ name }: string) {
return <span className="text-red-500">{name}</span>
}
export default React.memo(RenderName);
Рассмотрим компонент выше (child-component) без React.memo() компонента высшего порядка (HOC) у нас будут проблемы с повторным рендерингом, когда имя, переданное компоненту RenderName, будет одинаковым; но React.memo() HOC помогает предотвратить этот ненужный повторный рендеринг.
NB: memo не оптимизирует функцию, передаваемую дочернему компоненту, поэтому нам нужен React.useCallback().
Понимание React.useCallback()
/**
* Explanation:
* a password field that handles users password
* and provides a toggle for the password
*
* @returns JSX.Element (a styled password field)
*/
import React from 'react';
import eye from 'images/eye.svg';
import eyeClose from 'images/eye-close.svg';
function PasswordInput() {
const [show, setShow] = React.useState<boolean>(false);
const toggleSecret = React.useCallback(() => setShow(x => !x), []);
return (
<div className="h-8 flex items-center">
<input type="password" className="..." placeholder="Enter Password" />
<button onClick={toggleSecret}>
<img src={show ? eyeClose : eye} alt="toggle secret" />
</button>
</div>
);
}
export default PasswordInput;
С помощью React.useCallback() функция toggleSecret() мемоизируется, и каждый раз, когда вы нажимаете на кнопку переключения, она не вызывает повторного рендеринга, что повышает оптимизацию.
Примечание: мы передали функцию стрелки в React.useCallback(). функция стрелки имеет вид:
() => setShow((x) => !x)
React.useCallback() также помогает предотвратить повторный рендеринг, когда функция передается дочернему компоненту. Это делается путем «сохранения» функции, переданной дочернему компоненту, в то время как родительский компонент повторно рендерится.
Понимание React.useMemo()
/**
* Explanation:
* The code demonstrates how to create a DynamicTable using React's useMemo() function.
* The DynamicTable component is a wrapper around the Table component.
* The DynamicTable component is responsible for creating the columns and data for the Table component.
*
* @param {values: Record<string, string>[] | null}
* @returns returns a JSX.Element(Table)
*/
import React, { useMemo } from 'react';
import Table, { ColumnsProps } from './Table';
interface DynamicTableType {
values: Record<string, string>[] | null;
}
const DynamicTable = ({ values }: DynamicTableType): JSX.Element => {
const columns: ColumnsProps[] = useMemo(() => {
if (!values) return [];
const keys = Object.keys(values?.[0]);
const result = [];
for (let index = 0; index < keys.length; index++) {
const element = keys[index];
result.push({
Header: element?.replace('_', ' '),
accessor: element,
});
}
return result;
}, [values]);
const data: Record<string, string>[] = useMemo(() => {
if (!values) return [];
const result: Record<string, string>[] = [];
for (let index = 0; index < values.length; index++) {
const element = values[index];
result.push(element);
}
return result;
}, [values]);
return <Table columns={columns} data={data} showSearch={false} />;
};
export default DynamicTable;
Выдержка из проекта с открытым исходным кодом, над которым я сейчас работаю, проверьте его на github
Вся идея React.useMemo() похожа на идею React.useCallback(); но в React.useMemo() результат, возвращенный из вычисления функции, кэшируется, поэтому вам не нужно повторять такое дорогостоящее вычисление (при условии, что ваш зависимый массив useMemo не меняется). В приведенном выше примере столбцы & data являются мемоизированным значением.
Заключение
В целом, оптимизация — это то, о чем мы должны заботиться как инженеры, и такие простые техники, как кэширование, могут помочь нам предотвратить проблемы с перерисовкой/оптимизацией и т.д. Мемоизация нужна только тогда, когда вы работаете с дорогостоящими вычислениями.
Я доступен для технических переговоров по структуре данных, алгоритмам, javascript, react и react-native; вы можете связаться со мной через twitter или электронную почту.
Я также скоро запущу канал на youtube, чтобы рассказать о своих приключениях со структурой данных и алгоритмами. На канале я буду решать некоторые вопросы по leetcode и любые другие материалы для интервью, которые попадут мне в руки. следите 😊.
Сноски
Спасибо, что ознакомились с этим учебником. (пожалуйста, ставьте лайк и добавляйте свои комментарии)
Вы также можете ознакомиться с другими моими статьями в моем блоге.
Если у вас есть какие-либо вопросы, отзывы или комментарии, пожалуйста, дайте мне знать.
Вы можете связаться со мной через twitter email github
Вы также можете связаться со мной (я занимаюсь React-Native & React Js) twitter email