В чем разница между useCallback и useMemo на практике?

Ошибка вызвана тем, что на SQL-сервере не может быть строки, размер которой превышает 8 КБ (размер 1 страница), поскольку строки не разрешены для охвата страниц - это основной предел SQL Server, вы можете прочитать больше о это здесь:

Обратите внимание, что SQL-сервер позволит вы должны создать таблицу, однако, если вы попытаетесь фактически вставить какие-либо данные, которые охватывают несколько страниц, тогда она даст указанную выше ошибку.

Конечно, это не совсем похоже, потому что если выше было целая правда, тогда один столбец VARCHAR(8000) заполнит строку в таблице! (Это имело место). SQL Server 2005 обошел это ограничение, разрешив хранить некоторые данные из строки на другой странице и вместо этого вместо этого оставил 24-байтовый указатель. Вы можете прочитать об этом здесь:

Как вы можете видеть, теперь это означает, что теперь строки могут охватывать несколько страниц, однако одиночные строки столбцов по-прежнему должны вписываться в одну страницу (следовательно, максимальная размер столбца VARCHAR(8000)), и все еще существует ограничение на общее количество таких столбцов, которое вы можете иметь (около 8000/24 ​​= ~ 300 по моей оценке)

Конечно, это все отсутствует главное, что 400 широких столбцов на одной таблице абсурдны !!!

Вы должны внимательно изучить схему базы данных и придумать что-то более разумное - вы можете начать с выбора некоторые более консервативные оценки размеров столбцов (например, VARCHAR(255) или VARCHAR(50)), но вам действительно нужно разбить некоторые из этих полей на отдельные таблицы.

15
задан java-man-script 2 March 2019 в 21:40
поделиться

2 ответа

Вы вызываете запомненный обратный вызов каждый раз, когда вы делаете:

const calcCallback = useCallback(() => expensiveCalc('useCallback'), [neverChange]);
const computedCallback = calcCallback();

Вот почему счет useCallback увеличивается. Однако функция никогда не меняется, она никогда не создает ***** новый обратный вызов, он всегда один и тот же. Значение useCallback правильно выполняет свою работу.

Давайте сделаем некоторые изменения в вашем коде, чтобы убедиться, что это правда. Давайте создадим глобальную переменную lastComputedCallback, которая будет отслеживать, возвращается ли новая (другая) функция. Если возвращается новая функция, это означает, что useCallback просто «выполняется снова». Поэтому, когда он снова запустится, мы назовем expensiveCalc('useCallback'), так как вы рассчитываете, если useCallback сработал. Я делаю это в приведенном ниже коде, и теперь ясно, что useCallback запоминается, как и ожидалось.

Если вы хотите, чтобы useCallback воссоздала функцию каждый раз, тогда раскомментируйте строку в массиве, который проходит second. Вы увидите, как он воссоздает функцию.

'use strict';

const { useState, useCallback, useMemo } = React;

const neverChange = 'I never change';
const oneSecond = 1000;

let lastComputedCallback;
function App() {
  const [second, setSecond] = useState(0);
  
  // This                   
0
ответ дан Noitidart 2 March 2019 в 21:40
поделиться

TL; DR;

  • useMemo для запоминания результата вычисления между вызовами функции и между рендерами
  • useCallback для запоминания самого обратного вызова (ссылочное равенство) между рендерами
  • useRef для сохранения данных между рендерами (обновление не запускает повторный рендеринг)
  • useState для хранения данных между рендерами (обновление будет запускать ре рендеринг)

Длинная версия:

useMemo фокусируется на избежании тяжелых вычислений.

useCalback фокусируется на другом: исправляет проблему с производительностью, когда встроенные обработчики событий, такие как onClick={() => { doSomething(...); }, делают PureComponent дочерний повторный рендеринг (так как выражение функции там каждый раз ссылочно отличается)

Это говорит useCallback ближе к useRef, чтобы еще больше запомнить результат расчета.

PS Изучая документы , я согласен, что это выглядит странно.

useCallback вернет запомненную версию обратного вызова, которая изменяется только в случае изменения одного из входов. Это полезно при передаче обратных вызовов оптимизированным дочерним компонентам, которые полагаются на равенство ссылок для предотвращения ненужных рендеров (например, shouldComponentUpdate).

В примере

предположим, что у нас есть дочерний элемент PureComponent <Pure/>, который будет повторно визуализировать только после изменения его props

[1141 ] Следующий код переопределяет дочерний элемент каждый раз, когда переопределяется родительский элемент - поскольку встроенная функция каждый раз референциально отличается

function Parent({ ... }) {
  const [a, setA] = useState(0);
  ... 
  return (
    ...
    <Pure onChange={() => { doSomething(a); }} />
  );
}

Мы можем справиться с этим с помощью useCallback

function Parent({ ... }) {
  const [a, setA] = useState(0);
  const onPureChange = useCallback(() => {doSomething(a);});
  ... 
  return (
    ...
    <Pure onChange={onPureChange} />
  );
}
[ 1143] Но как только a изменится, мы обнаружим, что onPureChange, который мы создали, и запомнившийся для нас React все еще указывает на старое значение a! У нас ошибка вместо проблемы с производительностью! Это связано с тем, что onPureChange использует функцию закрытия для доступа к переменным (не для доступа по имени переменной). Чтобы сделать это правильно, нам нужно дать React знать, куда добавить onPureChange, и заново создать / запомнить (запомнить) новую версию, которая указывает на правильные данные. И здесь нам нужен второй аргумент:

const [a, setA] = useState(0);
const onPureChange = useCallback(() => {doSomething(a);}, [a]);

Теперь, если a изменено, React повторно рендерит компонент (это ход useState). И во время повторного рендеринга он обнаруживает, что входные данные для onPureChange отличаются, и возникает необходимость заново создать / запомнить новую версию обратного вызова. Наконец-то и все работает!

0
ответ дан skyboyer 2 March 2019 в 21:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: