Рубрики
Без рубрики

React запрос оптимизации рендеринга

Отказ от ответственности: оптимизация рендеринга является продвинутой концепцией для любого приложения. React Query уже поставляется с … Tagged с React, JavaScript, TypeScript, WebDev.

Отказ от ответственности : Оптимизация рендеринга является продвинутой концепцией для любого приложения. React Query уже поставляется с очень хорошими оптимизациями и по умолчанию из коробки, и большую часть времени не требуется дальнейших оптимизаций. «Недовые повторные ресурсы»-это тема, на которой многие люди склонны уделять большое внимание, поэтому я решил ее осветить. Но я хотел еще раз указать, что, как правило, для большинства приложений оптимизации, вероятно, не имеют большого значения, как вы думаете. Повторные ресурсы-это хорошая вещь. Они следят за тем, чтобы ваше приложение было в курсе. Я бы взял «ненужный повторный рендеринг» по поводу «пропавшего рендеринга-который мог бы каждый день» каждый день. Для получения дополнительной информации по этой теме, пожалуйста, прочитайте:

Я уже много написал о оптимизации рендеринга при описании опции SELECT в #2: React React Data Transformations Анкет Тем не менее, «почему React React Re-Render мой компонент два раза, хотя в моих данных ничего не изменилось»-это вопрос, на который мне, вероятно, нужно было ответить больше всего (кроме, возможно,: «где я могу найти документы V2»). Итак, позвольте мне попытаться объяснить это подробно.

Я не был совершенно честен в Последний пример Когда я сказал, что этот компонент будет повторно повторно, если длина Todos изменится:

export const useTodosQuery = (select) => useQuery(['todos'], fetchTodos, { select })
export const useTodosCount = () => useTodosQuery((data) => data.length)

function TodosCount() {
    const todosCount = useTodosCount()

    return 
{todosCount.data}
}

Каждый раз, когда вы делаете фоновый переизбыток, этот компонент будет дважды повторно рендеринг со следующей информацией о запросе:

{ status: 'success', data: 2, isFetching: true }
{ status: 'success', data: 2, isFetching: false }

Это потому, что React Query раскрывает много мета -информации для каждого запроса и Isfetching один из них. Этот флаг всегда будет правдой, когда запрос в полете. Это весьма полезно, если вы хотите отобразить индикатор фоновой загрузки. Но это также довольно ненужно, если вы этого не делаете.

notifyOnchangeProps

Для этого варианта использования React Query имеет notifyOnchangeProps вариант. Это может быть установлено на уровне для каждого наблюдателя, чтобы указать запрос React: Пожалуйста, сообщите этому наблюдателю об изменениях, если один из этих реквизитов изменит. Установив эту опцию на ['данные'] , мы найдем оптимизированную версию, которую мы ищем:

export const useTodosQuery = (select, notifyOnChangeProps) =>
    useQuery(['todos'], fetchTodos, { select, notifyOnChangeProps })
export const useTodosCount = () => useTodosQuery((data) => data.length, ['data'])

Вы можете увидеть это в действии в оптимистичный тип датчиков Пример в документах.

Оставаться в синхронизации

Хотя приведенный выше код работает хорошо, он может довольно легко выйти из синхронизации. Что если мы хотим отреагировать на Ошибка , слишком? Или мы начинаем использовать Isloading флаг? Мы должны сохранить notifyOnchangeProps Список синхронизации с любыми полями, которые мы на самом деле используем в наших компонентах. Если мы забудем это сделать, и мы только наблюдаем данные собственность, но получите Ошибка То, что мы также отображаем, наш компонент не будет повторно рендеринг и, таким образом, устареет. Это особенно хлопотно, если мы жестко кодируем это в нашем пользовательском крючке, потому что крюк не знает, что на самом деле будет использовать компонент:

export const useTodosCount = () => useTodosQuery((data) => data.length, ['data'])

function TodosCount() {
    // 🚨 we are using error, but we are not getting notified if error changes!
    const { error, data } = useTodosCount()

    return (
        
{error ? error : null} {data ? data : null}
) }

Как я намекал в отказе от ответственности вначале, я думаю, что это намного хуже, чем случайный ненужный повторный рендеринг. Конечно, мы можем передать эту опцию на пользовательский крючок, но он все еще чувствует себя довольно ручной и шаблонной. Есть ли способ сделать это автоматически? Оказывается, есть:

Отслеживаемые запросы

Я очень горжусь этой функцией, учитывая, что это был мой первый большой вклад в библиотеку. Если вы установите notifyOnchangeProps к 'отслеживаются' , React Query будет отслеживать поля, которые вы используете во время рендеринга, и будет использовать это для вычисления списка. Это будет оптимизировать точно так же, как указание списка вручную, за исключением того, что вам не нужно думать об этом. Вы также можете включить это по всему миру для всех ваших запросов:

const queryClient = new QueryClient({
    defaultOptions: {
        queries: {
            notifyOnChangeProps: 'tracked',
        },
    },
})
function App() {
    return (
        
            
        
    )
}

С этим вам больше никогда не придется думать о повторных ресурсах. Конечно, отслеживание использования также имеет немного накладных расходов, поэтому убедитесь, что вы используете это мудро. Есть также некоторые ограничения для отслеживаемых запросов, поэтому это функция Opt-In:

// 🚨 will track all fields
const { isLoading, ...queryInfo } = useQuery(...)

// ✅ this is totally fine
const { isLoading, data } = useQuery(...)
  • Отслеживаемые запросы работают только «во время рендеринга». Если вы получаете доступ только поля во время эффектов, они не будут отслеживаться. Это довольно краевой случай, хотя из -за массивов зависимостей:
const queryInfo = useQuery(...)

// 🚨 will not corectly track data
React.useEffect(() => {
    console.log(queryInfo.data)
})

// ✅ fine because the dependency array is accessed during render
React.useEffect(() => {
    console.log(queryInfo.data)
}, [queryInfo.data])
  • Отслеживаемые запросы не сброшены на каждом рендеринге, поэтому, если вы отслеживаете поле один раз, вы отслеживаете его на протяжении всей жизни наблюдателя:
const queryInfo = useQuery(...)

if (someCondition()) {
    // 🟡 we will track the data field if someCondition was true in any previous render cycle
    return 
{queryInfo.data}
}

Другая, но не менее важная оптимизация рендеринга, которая реагирует, запрос, включенный из коробки, является Структурный обмен . Эта функция гарантирует, что мы сохраняем референциальную идентичность нашего данные на каждом уровне. В качестве примера, предположим, что у вас есть следующая структура данных:

[
    { "id": 1, "name": "Learn React", "status": "active" },
    { "id": 2, "name": "Learn React Query", "status": "todo" }
]

Не предположим, что мы переходим наш первый тодо в Готово Государство, и мы делаем фоновый переигрыш. Мы получим совершенно новый JSON от нашего бэкэнда:

[
-    { "id": 1, "name": "Learn React", "status": "active" },
+    { "id": 1, "name": "Learn React", "status": "done" },
    { "id": 2, "name": "Learn React Query", "status": "todo" }
]

Теперь React Query попытается сравнить старое состояние и новое и сохранить как можно большую часть предыдущего состояния. В нашем примере массив Todos будет новым, потому что мы обновили Todo. Объект с идентификатором 1 также будет новым, но объект для ID 2 будет той же ссылкой, что и в предыдущем состоянии – запрос React просто скопирует его с новым результатом, потому что в нем ничего не изменилось.

Это очень удобно при использовании селекторов для частичных подписок:

// ✅ will only re-render if _something_ within todo with id:2 changes
// thanks to structural sharing
const { data } = useTodo(2)

Как я намекал ранее, для селекторов, структурный обмен будет выполнен дважды: один раз на результат, возвращенный из QueryFN, чтобы определить, что -то что -то изменилось, а затем еще раз на результат функции селектора. В некоторых случаях, особенно при наличии очень больших наборов данных, структурный обмен может быть узким местом. Это также работает только на данных JSON-сериализации. Если вам не нужна эта оптимизация, вы можете отключить ее, настройка Структурное обмен: ложь по любому запросу.

Посмотрите на Заменить тесты Если вы хотите узнать больше о том, что происходит под капюшоном.

Фу, это было довольно много. Не стесняйтесь обращаться ко мне в Twitter Если у вас есть какие -либо вопросы или просто оставьте комментарий ниже ⬇. Я всегда рад помочь!

Оригинал: “https://dev.to/tkdodo/react-query-render-optimizations-26k6”