Многие разработчики продолжают использовать хуки useState и useEffect для обновления состояний, но мне такой подход не нравится. Проблема в том, что это приводит к одновременному монтированию, перемонтированию и размонтированию компонента, что приводит к неожиданному поведению. В результате при вводе чего-либо в консоль вы можете увидеть повторение результата три раза.

Представляем хук useLoaderData:

Хук useLoaderData — это пользовательский хук в React, который помогает вам загружать данные в ваш компонент. Это упрощает процесс извлечения данных из API или выполнения любой асинхронной операции.

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

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

Используя хук useLoaderData, вы можете поддерживать чистоту и организованность кода вашего компонента, отделяя логику загрузки данных от остальных обязанностей вашего компонента. Это позволяет вам легко извлекать данные и управлять ими более удобным для новичков способом.

Зачем использоватьLoaderHook?

Использование useLoaderHook из react-router помогает достичь той же функциональности с минимальными усилиями. Вот несколько примеров того, почему вы должны его использовать.

  • Управление состоянием загрузки: загрузчики управляют состоянием загрузки для вас, предоставляя четкое указание о том, когда данные извлекаются. Это поможет вам управлять счетчиками загрузки, индикаторами выполнения или любыми другими элементами пользовательского интерфейса, связанными с загрузкой данных.
  • Обработка ошибок. Загрузчики часто включают механизмы обработки ошибок, позволяющие обрабатывать и отображать ошибки, возникающие в процессе загрузки данных. Они обеспечивают стандартизированный способ обработки ошибок, упрощая реализацию согласованной обработки ошибок в вашем приложении.
  • Разделение проблем. Загрузчики позволяют отделить логику загрузки данных от других аспектов вашего компонента. Это способствует лучшей организации кода и удобству сопровождения, поскольку вы можете сосредоточиться на конкретных обязанностях, не смешивая их.

И многое другое.

Давайте посмотрим, как это работает.

Предполагается, что вы хорошо знаете, как работает react-router 6. Если вы этого не сделаете, не стесняйтесь проверить документы здесь

Во-первых, нам нужно настроить систему маршрутизации в нашем приложении для работы с Loader API. До сих пор мы использовали настройку BrowserRouter для обработки различных маршрутов для нашего приложения.
Давайте немного поговорим об этом.

import { BrowserRouter, Routes, Route, Outlet } from "react-router-dom"
import HomeComponent from "./home"
import AboutCompoent from "./about"
function App () {
    <BrowserRouter>
        <Routes>
            <Route path='/' element={<Outlet />}>
                <Route index element={<HomeComponent /> } />
                <Route path='about' element={<AboutComponent/> } />
            </Route>
        </Routes>
    </BrowserRouter>
};
export default App;

Здесь мы настроили систему маршрутизации, традиционно используя импорт из react-router.
Задумайтесь на секунду о том, что происходит.

Хорошо. BrowserRouter из react-router создает массив объектов из Routes дочерних элементов. Фрагмент ниже дает четкую иллюстрацию того, как это работает.

BrowserRouter([
{
    path: '/',
    element: <HomeComponent />,
    children: []
},
{
    path: '/about',
    element: <AboutComponent/>,
    children: []
}
])

Если они должны были быть вложенными маршрутами, то он добавляет дочерний маршрут к дочернему ключу в родительском маршруте.
Да, именно так он остается рекурсивным.

Однако этот метод нельзя использовать для использования хука loaderData. Нам нужно сделать небольшой рефакторинг. Не паникуйте, это немного похоже на это. Я настоятельно рекомендую вам ознакомиться с документацией по реакции-маршрутизатору для получения дополнительной информации.

import { 
createBrowserRouter,
createRoutesFromElements,
RouterProvider,
Route, 
Outlet
 } from "react-router-dom"

import HomeComponent from "./home"
import AboutComponent from "./about"

function App() {
    const browserRoutes = createBrowserRouter(createRoutesFromElements(
       <Route path='/' element={<Outlet />}>
                <Route index element={<HomeComponent /> } />
                <Route path='about' element={<AboutComponent /> } />
        </Route>
    ))

     return (
        <RouterProvider router={browserRoutes} />
    );
}

Я импортировал createBrowserRouter, createRoutesFromElement, RouterProvider.
Затем инициализируйте переменную с именем browserRoutes, чтобы она служила тем объектом, который должен быть отрисован. Заметил, что я вызвал функцию createRoutesFromElements внутри функции createBrowserRouter. Это произошло потому, что я хочу проанализировать или преобразовать маршруты в объект, и createRoutesFromElements, как следует из названия, может помочь мне в этом. Затем, наконец, RouterProvider было возвращено со значением нового browserRouter. Давайте посмотрим, что бы мы сделали без использования функции createRoutesFromElements.

createBrowserRouter([
{
    path: '/',
    element: <HomeComponent />,
    children: []
},
{
    path: '/about',
    element: <AboutComponent/>,
    children: []
}])

Я не большой поклонник этого, так как ваш маршрут может даже быть вложенным, и в какой-то момент это становится запутанным. Вы должны держать вещи очень простыми.

Изучение функций загрузчика:

Поскольку теперь у нас есть некоторое представление о том, как мы можем настроить наше приложение для использования API загрузчика, давайте посмотрим, как мы можем использовать этот API.

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

import { useState } from 'react'

const HomeComponent = () => {
    const [data, setData] = useState([]);
    
    useEffect(async () => {
        const request = await fetch('http://localhost:3004/file');
         if(!request.ok) throw new Error('Failed to fetch data')
        const item= await request.json()
        setData(item)  
    }, [])

    return (
        <section>
            { data.length > 0 ? data.map((foundData) => (
                    <div key={foundData.id}>
                        <strong>{foundData.name}</strong>
                     </div>
                 )) : <p>Data currently unavailable</p>}
        </section>
    )
}
export default HomeComponent

Это тонна строк, так как мы могли бы немного упростить это и, возможно, повторно использовать ту же функцию.

Чтобы использовать загрузчики, необходимо определить функцию загрузчика. Функции загрузчика похожи на Пользовательские хуки.
Кроме того, соглашение об именах функций не имеет значения, поскольку вы можете называть их как угодно. В приведенном ниже фрагменте кода я создам базовую функцию загрузчика, которая извлекает данные из API, как показано в приведенном выше фрагменте.

export async function LoaderFunction () {
    const request = await fetch('http://localhost:3004/file');
    if (!request.ok) throw new Error ('Failed to fetch item')
    const item = await  response.json();
    return item;
};

Теперь нам нужно импортировать функцию загрузчика в компонент, где обрабатываются наши маршруты. После настройки системы маршрутизации с использованием createBrowserRouter и createRouteFromElements у вас должен быть доступ к реквизиту под названием loader. Там вы должны передать созданное вами LoaderFunction в качестве значения.
В приведенном ниже фрагменте кода это наглядно показано.

import { 
createBrowserRouter,
createRoutesFromElements,
RouterProvider,
Route, 
Outlet
 } from "react-router-dom"
import HomeComponent from "./home"
import AboutComponent from "./about"
import { LoaderFunction as HomeLoader} from "./loader"

function App() {
    const browserRoutes = createBrowserRouter(createRoutesFromElements(
       <Route path='/' element={<Outlet />}>
                <Route index element={<HomeComponent /> }
                     loader={HomeLoader}/>
                <Route path='about' element={<AboutComponent /> } />
        </Route>
    ))

     return (
        <RouterProvider router={browserRoutes} />
    );
}

После этого мы можем получить доступ к данным, возвращаемым функцией загрузчика, с помощью useLoaderDataхука из react-router в HomeComponent.
Фрагмент кода ниже лучше всего объясняет то, что только что было прочитано.

import { useLoaderData } from "react-router-dom"

const HomeComponent = () => {
    const data = useLoaderData();

    return (
        <section>
            {data.map((foundData) => (
                    <div key={foundData.id}>
                         <strong>{foundData.name}</strong> 
                    </div> 
            ))}
        </section>
    )
}
export default HomeComponent

Вау! 😲..
Теперь посмотрите, как мы только что очистили HomeComponent :)
Заметили, что мы избавились от сторожевого предложения, которое проверяет, являются ли данные нулевыми.
Это связано с тем, что react-router загружает данные, как только URL-адрес/путь становится активным. Таким образом, он делает необходимые запросы еще до того, как компонент смонтирован. Да!

Мы только делаем условия для счастливого пути. Что, если мы передадим несуществующую конечную точку? Если это так, не паникуйте, так как react-router также позволяет нам передавать компоненты другому свойству с именем errorElement .
Это специально для ошибок, так же как мы используем ErrorBoundaries. Давайте посмотрим, как это работает во фрагменте ниже.

import { 
createBrowserRouter,
createRoutesFromElements,
RouterProvider,
Route, 
Outlet
 } from "react-router-dom"
import HomeComponent from "./home"
import AboutComponent from "./about"
import { LoaderFunction as HomeLoader} from "./loader"

function App() {
    const browserRoutes = createBrowserRouter(createRoutesFromElements(
       <Route path='/' element={<Outlet />}>
                <Route index element={<HomeComponent /> }
                    loader={HomeLoader} errorElement={<h1>An Error occured</h1>}/>
                <Route path='about' element={<AboutComponent /> } />
        </Route>
    ))

     return (
        <RouterProvider router={browserRoutes} />
    );
}

Я только что использовал тег заголовка, чтобы показать ошибку. Желательно, чтобы вы использовали компонент, чтобы вы также могли получить доступ к хуку useRouteError. Я покажу, как использовать хук useRouteError, в одном из моих будущих постов в блоге. Если вы хотите узнать об этом, пожалуйста, используйте эту ссылку.
Поскольку он предварительно извлекает данные перед монтированием компонента, состояние загрузки становится неактуальным, поскольку он может либо получить данные, либо вернуть сообщение об ошибке. вы передаете в качестве значения свойства errorElement.

Это все, что вам нужно знать об отправке запросов с помощью API уровня данных.

Если вы нашли это полезным, подпишитесь на меня в Twitter, отреагируйте на это сообщение, оставьте комментарий или поддержите меня, купив мне кофе по этой ссылке. .