Автор Самуэль Огунлее✏️
Изучение множества фреймворков в мире фронтенд-технологий не только увлекательно, но и может стать разумным карьерным шагом и хорошей практикой для будущих проектов. В случае, если вы снова столкнетесь с новым фреймворком, вы будете готовы к работе.
Refine — это еще один замечательный фреймворк, который был недавно выпущен, чтобы уменьшить напряжение разработчиков в таких областях, как маршрутизация, аутентификация и управление состояниями.
В этой статье мы рассмотрим, как Refine, фреймворк на основе React, может помочь разработчикам, использующим его встроенные функции, создав простое веб-приложение, демонстрирующее аутентификацию пользователей и маршрутизацию.
Что такое Refine?
Refine — это фреймворк на основе React для быстрой разработки приложений с большим объемом данных. Он использует систему Ant Design — инструментарий пользовательского интерфейса, ориентированного на бизнес.
Refine поставляется с большим количеством готовой функциональности, чтобы помочь вам быстро начать работу без потери настраиваемости. Маршрутизация, сетевое взаимодействие, аутентификация, управление состояниями и интернационализация являются примерами такой функциональности.
Суперспособность Refine — полный контроль над пользовательским интерфейсом. Он отлично подходит для приложений, которым необходимо обрабатывать большие объемы данных, например, для административных панелей и приборных панелей, и обеспечивает поддержку баз данных REST и GraphQL, включая Strapi и NestJS CRUD.
Предварительные условия
Чтобы понять этот учебник, вам понадобятся:
- React v16 или новее
- Рабочие знания о React
- Знание Node.js
- текстовый редактор
Использование крючков Refine
Прежде чем мы приступим к созданию нашего примера приложения, давайте рассмотрим одну из лучших функций Refine: крючки. Хуки Refine значительно облегчили разработчикам интеграцию с веб-приложениями. Лучше всего то, что крючки Refine включают в себя несколько дополнительных функций в дополнение к встроенным крючкам React, на которых они основаны.
Хуки данных, которые включают useCreate
, useUpdate
, useDelete
, useCustom
и useApiUrl
, являются некоторыми из дополнительных функций, предлагаемых Refine. Они похожи на крючки, которые вы можете найти в React Query — ознакомьтесь с документацией, чтобы узнать больше о крючках данных Refine.
В этой статье мы сосредоточимся в основном на крючках авторизации, поскольку мы будем реализовывать их позже, когда создадим наш пример приложения.
Хуки авторизации Refine
Эти хуки помогают в аутентификации веб-приложений. Они предоставляют нам такие суперспособности, как возможность аутентификации пользователей для входа в систему, выхода из нее или проверки соответствия существующего пользователя определенным критериям перед доступом к защищенным маршрутам. В нем используются следующие функции:
Во-первых, useLogin
вызывает метод входа authProvider
, который аутентифицирует приложение, если метод входа успешен, и выводит уведомление об ошибке в случае неудачи. После успешной аутентификации он возвращает пользователя в базовое приложение:
import { useLogin, Form } from "@pankod/refine";
export const LoginPage = () => {
const { mutate: login } = useLogin()
const onSubmit = (values) => {
login(values);
};
return (
<Form onFinish={onSubmit}>
// rest of the login form
</Form>
)
}
Далее useLogout
вызывает метод выхода из системы authProvider
под капотом. Если метод выхода authProvider
работает успешно, он аутентифицирует приложение; если он не работает, состояние аутентификации остается неизменным.
Посмотрите на короткий фрагмент ниже, чтобы увидеть этот хук в действии:
import { useLogout, Button } from "@pankod/refine";
export const LogoutButton = () => {
const { mutate: logout } = useLogout();
return (
<Button onClick={() => logout()}>
Logout
</Button>
)
}
useCheckError
вызывает функцию authProvider
checkError
. useCheckError
запускает метод выхода из приложения authProvider
, если checkError
возвращает обещание отказа, и приложение не аутентифицировано:
import { useCheckError } from "@pankod/refine";
const { mutate: checkError } = useCheckError();
fetch("https://api.fake-rest.refine.dev/users)
.then(() => console.log("Success"))
.catch((error) => checkError(error));
Наконец, useAuthenticated
вызывает метод authProvider
checkAuth
, который проверяет наличие определенных и защищенных действий.
Табличные крючки
Используя хук useTable()
, вы можете получить доступ к свойствам, совместимым с компонентом Ant Design Table
. Этот хук предлагает несколько функциональных возможностей, таких как сортировка, фильтрация и пагинация:
import React from "react";
import { List, Table, useTable } from "@pankod/refine";
export const Sample = () => {
const { tableProps } = useTable();
return (
<div>
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" />
</Table>
</List>
</div>
);
};
export default Sample;
Начало работы с Refine
В этом руководстве мы создадим простое приложение, которое будет выводить списки пользователей. Для начала мы создадим шаблон по умолчанию для Refine.
Есть два способа сделать это; первый — использовать супершаблон, а второй — Create React App. Мы будем использовать подход Create React App, основываясь на этом руководстве, потому что мы все фанаты React 😊.
В терминале создайте новое приложение React и выполните приведенную ниже команду:
yarn create react-app refine-react-framework
Это сгенерирует стартовый шаблон и создаст папку refine-react-framework
. Вот как должен выглядеть ваш файл package.json
:
Но мы еще не закончили; после создания шаблона React по умолчанию нам нужно будет выполнить приведенную ниже команду для установки пакета Refine:
yarn add @pankod/refine @pankod/refine-react-router
Это установит модуль Refine в приложение React, которое мы создали выше. Вот как теперь должен выглядеть ваш файл package.json
:
Модуль Refine был успешно установлен, как видно из строк шесть и семь. Теперь давайте запустим приложение с помощью команды ниже:
yarn start
Вот как должен выглядеть ваш вывод:
Давайте проведем некоторую очистку внутри проекта, который был создан выше, потому что есть несколько ненужных файлов, которые мы не будем использовать.
Откройте папку src
и удалите setupTests.js
, reportWebVitals.js
, logo.svg
, App.css
и toApp.test.js
из проекта. Это делается для уменьшения размера файла проекта, так как мы не будем их использовать.
Откройте App.js
и замените код на следующий:
const App = () => {
return (
<div>
Hello World
</div>
);
}
export default App;
Приведенный выше код просто удаляет предыдущее содержимое из шаблона, чтобы мы могли работать в чистой среде.
Еще один момент: наше приложение сломано, потому что мы удалили некоторые файлы, связанные внутри index.js
. Давайте исправим это, обновив файл с помощью приведенного ниже кода:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
Наконец, зайдите в файл index.css
и очистите его, чтобы он не содержал никакого кода.
Вы заметите, что мы не включили в наше приложение никаких сторонних библиотек пользовательского интерфейса. Почему? Потому что Refine поставляется со встроенной системой библиотек пользовательского интерфейса под названием Ant Design.
Другие библиотечные системы пользовательского интерфейса (такие как Chakra UI, Bootstrap и Material UI) также поддерживаются Refine. В этой статье мы будем использовать систему Ant Design, которая используется по умолчанию.
Создание простого веб-приложения с помощью Refine
Теперь давайте замажем руки и посмотрим, как работает Refine в простом приложении для создания списка пользователей. Это приложение будет получать произвольные данные из конечной точки и предоставлять их пользователю в табличном виде с функцией постраничного просмотра.
Мы будем использовать некоторые воображаемые данные REST API, предоставленные JSON Server, инструментом, который генерирует поддельные REST API. Перед использованием API следует ознакомиться с документацией на сайте https://api.fake-rest.refine.dev/.
Давайте внесем некоторые изменения в проект, который мы начали в предыдущем разделе. Создайте папку pages
, папку component
и папку queries
внутри папки src
. Эти папки помогут разделить задачи, что приведет к хорошей организации кода.
Создайте подпапку users
внутри папки components, а в ней файл User.jsx
. Затем скопируйте и вставьте приведенный ниже код:
import React from "react";
import { List, Table, useTable } from "@pankod/refine";
export const Users = () => {
const { tableProps } = useTable({
initialSorter: [
{
field: "title",
order: "asc",
},
],
});
return (
<div>
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" sorter />
<Table.Column dataIndex="firstName" title="First Name" sorter />
<Table.Column dataIndex="lastName" title="Last name" sorter />
<Table.Column dataIndex="email" title="Email" sorter />
<Table.Column dataIndex="birthday" title="Birthday" sorter />
</Table>
</List>
</div>
);
};
export default Users;
Вот где происходит настоящий фокус! В этом сценарии некоторые компоненты были импортированы в сочетании с хуком useTable
.
Помните, что здесь используются все компоненты Ant Design, и они создают коллекцию уникальных таблиц, которые будут использоваться для заполнения определенных данных в ходе проекта. Давайте подробнее рассмотрим приведенный выше код.
Крючки являются большой частью Refine, и useTable()
— важный крючок, как мы узнали ранее. Здесь хук useTable()
получает данные из API и оборачивает их в различные вспомогательные хуки компонента. Задачи взаимодействия с данными, такие как сортировка, фильтрация и пагинация, будут доступны «на лету» с помощью этой единственной строки кода.
Параметр initialSorter
позволяет выбрать, какое поле будет начинаться с какого состояния сортировки ("asc"
или "desc"
). Он определяет, в каком порядке будут показаны данные — по возрастанию или по убыванию. Работает по свойству sorter
таблицы.
List
— это компонент Refine. Он служит оберткой для других элементов.
Table.Column
используется для отображения строк данных и сбора структурированных данных. Он также способен выполнять сортировку, поиск, пагинацию и фильтрацию.
rowKey
— это единственный в своем роде ключ-идентификатор для эффективной итерации.
Свойство dataIndex
служит уникальным идентификатором для каждой строки и столбца таблицы. Оно сопоставляет поле с соответствующим ключом из ответа API.
Давайте запустим наш терминал и посмотрим на результат в выбранном вами браузере; он должен выглядеть примерно так:
Получение данных для приложения
Теперь давайте используем поддельный REST API для получения полезной информации. Перейдите в папку queries
и создайте в ней файл GetData.jsx
. Скопируйте и вставьте приведенный ниже код в свой редактор:
import { Refine } from "@pankod/refine";
import routerProvider from "@pankod/refine-react-router";
import dataProvider from "@pankod/refine-simple-rest";
import { Users } from "components/users/Users";
export const GetData = () => {
const API_URL = "https://api.fake-rest.refine.dev";
return (
<Refine
routerProvider={routerProvider}
dataProvider={dataProvider(API_URL)}
resources={[{ name: "users", list: Users }]}
Layout={({ children }) => (
<div style={{ display: "flex", flexDirection: "column" }}>
{children}
</div>
)}
/>
);
};
export default GetData;
routerProvider
, dataProvider
, resources
и Layout
— это самые важные свойства, на которые следует обратить внимание. Это все свойства, которые были переданы компоненту Refine. Фиктивные данные будут сгенерированы в API_URL
.
Некоторые функции маршрутизатора, такие как страницы ресурсов, навигация и так далее, создаются в результате работы routerProvider
. Это дает вам возможность использовать любую библиотеку маршрутизаторов по вашему желанию.
Интерфейс между настраиваемым приложением и API называется провайдером данных, как показано выше dataProvider
. Он действует как интегратор Refine, упрощая разработчикам использование широкого спектра API и сервисов данных. Он использует установленные методы для отправки HTTP-запросов и получения данных в ответ.
Свойство resources
Refine представляет конечные точки API. Оно связывает свойство name
с определенной конечной точкой и автоматически генерирует URL, который будет присоединен к конечной точке; в данном случае присоединенный URL будет «/users».
Layout
— это пользовательский компонент, который позволяет вам создать новый шаблон и стиль без необходимости использовать шаблон по умолчанию. Он принимает дочерний аргумент, чтобы облегчить работу с будущими компонентами, которые поставляются внутри него.
Именованный импорт был использован, чтобы доставить компонент User
из компонента User
, который был создан ранее с помощью техники Table.Column
. Затем он добавляется к свойству resource, которое автоматически создает URL-путь для маршрутизации.
Теперь давайте внесем некоторые изменения в наш файл User.jsx
, добавив несколько дополнительных тегов для улучшения физической компоновки приложения.
Скопируйте и вставьте следующий код ниже:
import React from "react";
import {
Button,
Icons,
List,
Table,
useTable,
Typography,
} from "@pankod/refine";
export const Users = () => {
const { Title } = Typography;
const { tableProps } = useTable({
initialSorter: [
{
field: "title",
order: "asc",
},
],
});
return (
<div>
<Title
style={{
textAlign: "center",
fontSize: "2rem",
fontWeight: 600,
padding: "1rem",
color: "#67be23",
}}
>
Simple User Listing Application
</Title>
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" sorter />
<Table.Column dataIndex="firstName" title="First Name" sorter />
<Table.Column dataIndex="lastName" title="Last name" sorter />
<Table.Column dataIndex="email" title="Email" sorter />
<Table.Column dataIndex="birthday" title="Birthday" sorter />
</Table>
</List>
</div>
);
};
export default Users;
В приведенном выше коде были импортированы компоненты из "@pankod/refine"
, которые будут использоваться для создания пользователей для таблицы.
Для улучшения пользовательского опыта было введено несколько тегов, а сами теги были дополнены встроенной стилизацией.
Давайте перезапустим наш терминал и посмотрим на новый вывод в браузере:
Ура! Даже пагинация отлично работает с таблицей, которую мы использовали для создания данных, содержащей список пользователей.
Обратите внимание, что при использовании хука useTable
пагинация включается по умолчанию.
Создание динамической страницы входа в систему
Мы смогли создать простое приложение, которое отображает список случайных людей вместе с некоторой дополнительной информацией. Мы можем добавить немного остроты нашему приложению, создав динамическую страницу входа, которая не позволит пользователям получить доступ к созданному списку пользователей, пока они не пройдут аутентификацию.
В этом сценарии мы будем использовать сторонние библиотеки, такие как Google Authenticator, Axios и dotenv. Пользователи смогут аутентифицировать себя с помощью Google, отправлять запросы к конечным точкам REST с помощью Axios и сохранять секретные ключи API с помощью dotenv.
Скопируйте и вставьте следующую команду в терминал:
yarn add react-google-login axios dotenv
Это установит зависимости Google Authenticator, а также Axios для инициирования запросов и dotenv для сохранения секретных ключей. Ваш файл package.json
должен выглядеть примерно так:
Давайте приступим к работе с функциями Google Authenticator!
Перейдите в папку pages
и создайте в ней новый файл Login.jsx
. Именно в нем будет происходить процесс входа в систему. Скопируйте и вставьте приведенный ниже код в свой браузер:
import { Button, Icons, useLogin, Typography } from "@pankod/refine";
import { useGoogleLogin } from "react-google-login";
const { GoogleOutlined } = Icons;
const clientId = `${process.env.REACT_APP_CLIENT_ID}`;
export const Login = () => {
const { Title } = Typography;
const { mutate: login, isLoading } = useLogin();
const { signIn } = useGoogleLogin({
onSuccess: (response) => login(response),
clientId,
isSignedIn: true,
cookiePolicy: "single_host_origin",
});
return (
<div>
<div
style={{
background: "#fafafa",
height: "100vh",
display: "flex",
flexDirection: "column",
}}
>
<div>
<Title
style={{
textAlign: "center",
fontSize: "2rem",
fontWeight: 600,
padding: "2rem",
color: "#67be23",
}}
>
Simple User Listing Application
</Title>
</div>
<div style={{ margin: "auto" }}>
<Title
style={{
textAlign: "center",
fontSize: "1rem",
fontWeight: 300,
padding: "3rem 0 0 0",
color: "#67be23",
}}
>
Sign in with Google
</Title>
<Button
type="primary"
size="large"
block
icon={<GoogleOutlined />}
loading={isLoading}
onClick={() => signIn()}
>
Sign in
</Button>
</div>
</div>
</div>
);
};
Давайте рассмотрим приведенный выше код более подробно, чтобы понять, что происходит.
Нам нужно было импортировать несколько компонентов и хуков для нашей страницы входа, что мы и сделали.
Button
, Icon
и Typography
относятся к компонентам, а useLogin
и useGoogleLogin
— к хукам.
Button
выполняет ту же функцию, что и стандартный тег кнопки HTML, позволяя выполнить действие при нажатии на кнопку. Он включает компонент Icon
, состояние загрузки и метод onClick
, которые предоставляются в качестве реквизитов.
Typography
поддерживает текстовые функции, позволяя добавлять дополнительный текст заголовка к компоненту Title
.
useGoogleLogin
дает вам доступ к параметру signIn
. Этот параметр затем передается компоненту Button
, который запускает действие, когда пользователь нажимает на него.
useGoogleLogin
вызывает функцию onSuccess
, которая вызывается каждый раз, когда выполняется запрос на вход. Она проверяет правильность свойств, связанных с onSuccess
при каждом запуске, а затем аутентифицирует пользователя. Среди этих свойств ClientId
, isSignedIn
и cookiePolicy
.
Скопируйте ключ ID клиента и поместите его в файл .env
, который будет создан в корневой папке вашего приложения. Process.env
используется для синхронизации ключа ID клиента с приложением, которое будет его использовать.
Теперь создадим папку services
, которая будет обрабатывать все действия пользователя до начала работы приложения. Создайте файл authProvider.js
в этой папке и добавьте следующий код:
import axios from "axios";
export const authProvider = {
login({ tokenId, profileObj, tokenObj }) {
axios.defaults.headers.common = {
Authorization: `Bearer ${tokenId}`,
};
localStorage.setItem(
"user",
JSON.stringify({ ...profileObj, avatar: profileObj.imageUrl }),
);
localStorage.setItem("expiresAt", tokenObj.expires_at.toString());
return Promise.resolve();
},
logout() {
localStorage.removeItem("user");
localStorage.removeItem("expiresAt");
return Promise.resolve();
},
checkError() {
return Promise.resolve();
},
checkAuth() {
const expiresAt = localStorage.getItem("expiresAt");
if (expiresAt) {
return new Date().getTime() / 1000 < +expiresAt
? Promise.resolve()
: Promise.reject();
}
return Promise.reject();
},
getUserIdentity() {
const user = localStorage.getItem("user");
if (user) {
return Promise.resolve(JSON.parse(user));
}
},
};
В данном случае authProvider
был разработан для обработки операций аутентификации. Он принимает некоторые методы, которые выполняются при выполнении действия.
Метод login
принимает некоторые входные данные (tokenId
, profileObj
, tokenObj
), которые были получены от Google и будут использоваться в будущем приложении. Ответы временно сохраняются в localStorage
и затем вызываются при необходимости.
Метод logout
по существу удаляет все, что было установлено или сохранено в localStorage
.
Проверка подлинности осуществляется с помощью метода checkAuth
. Он проверяет, активна ли еще сессия пользователя и не была ли она использована; если нет, он возвращает пользователя на главную страницу.
После успешного входа в систему функция getUserIdentity
помогает получить сохраненные данные. Данные, которые ранее были сохранены на будущее, будут доступны и использованы здесь.
Теперь давайте обновим созданный ранее файл GetData.jsx
. Скопируйте и вставьте приведенный ниже код:
import { Refine } from "@pankod/refine";
import routerProvider from "@pankod/refine-react-router";
import dataProvider from "@pankod/refine-simple-rest";
import {authProvider} from "services/authProvider"
import axios from "axios";
import { Users } from "components/users/Users";
import { Login } from "pages/Login";
export const GetData = () => {
const API_URL = "https://api.fake-rest.refine.dev";
return (
<Refine
authProvider={authProvider}
routerProvider={routerProvider}
dataProvider={dataProvider(API_URL, axios)}
resources={[{ name: "users", list: Users }]}
LoginPage={Login}
reactQueryDevtoolConfig={{
initialIsOpen: false,
position: "none",
}}
Layout={({ children }) => (
<div style={{ display: "flex", flexDirection: "column" }}>
{children}
</div>
)}
/>
);
};
export default GetData;
Созданный ранее authProvider
был импортирован и передан в качестве свойства компоненту Refine.
Поскольку он действует как пользовательский компонент Login.jsx
, свойство LoginPage
также было предоставлено в компоненте Refine.
Axios
был передан в качестве параметра с API_URL
, поскольку он необходим для отправки запроса.
Давайте посмотрим на результаты в браузере. Вывод должен выглядеть следующим образом:
Когда пользователь выбирает кнопку Sign in, система аутентифицирует пользователя и перенаправляет его на страницу пользователя, которую мы создали ранее.
Создание кнопки выхода из системы
Итак, мы создали страницу списка пользователей и страницу входа в систему. Давайте завершим наше приложение, добавив кнопку выхода и сгенерировав некоторые динамические данные из localStorage
.
Скопируйте приведенный ниже код и вставьте его в файл Users.jsx
:
import React from "react";
import {
Button,
Icons,
List,
Table,
useTable,
useLogout,
Typography,
} from "@pankod/refine";
import { useGoogleLogout } from "react-google-login";
import { useGetIdentity } from "@pankod/refine";
export const Users = () => {
const { data: identity } = useGetIdentity()
const { Title } = Typography;
const { tableProps } = useTable({
initialSorter: [
{
field: "title",
order: "asc",
},
],
});
const { mutate: logout, isLoading } = useLogout();
const { GoogleOutlined } = Icons;
const clientId = `${process.env.REACT_APP_CLIENT_ID}`;
const { signOut } = useGoogleLogout({
onLogoutSuccess: (response) => logout(response),
clientId,
isSignedIn: false,
cookiePolicy: "single_host_origin",
});
return (
<div>
<Title
style={{
textAlign: "center",
fontSize: "2rem",
fontWeight: 600,
padding: "1rem",
color: "#67be23",
}}
>
Simple User Listing Application
</Title>
<div
style={{
display: "flex",
justifyContent: "space-between",
padding: "0 1.5rem",
}}
>
<Title
style={{
fontSize: "1.2rem",
}}
>
<img
style={{ borderRadius: "50%", marginRight: "1rem", height: "60px" }}
src={identity?.imageUrl}
alt=""
/>
Welcome <span style={{ color: "#67be23" }}> {identity?.name}!</span>
</Title>
<Button
type="primary"
size="large"
htmlType="submit"
icon={<GoogleOutlined />}
loading={isLoading}
onClick={() => signOut()}
>
Sign out
</Button>
</div>
<List>
<Table {...tableProps} rowKey="id">
<Table.Column dataIndex="id" title="ID" sorter />
<Table.Column dataIndex="firstName" title="First Name" sorter />
<Table.Column dataIndex="lastName" title="Last name" sorter />
<Table.Column dataIndex="email" title="Email" sorter />
<Table.Column dataIndex="birthday" title="Birthday" sorter />
</Table>
</List>
</div>
);
};
export default Users;
В данном случае мы использовали хуки useGoogleLogout()
и useGetIdentity()
.
В файле authProvider
был объявлен хук useGetIdentity()
. Он предоставляет доступ к параметру identity
, который будет использован для получения некоторых данных localStorage
.
Крючок useGoogleLogout()
похож на крючок useGoogleLogin()
, поскольку выполняет противоположную функцию, позволяя использовать параметр signOut
. Когда пользователь нажимает на кнопку, этот параметр передается компоненту Button
, который выполняет действие.
Метод onLogoutSuccess
выполняется всякий раз, когда запрос на выход из системы выполняется с помощью useGoogleLogin()
.
identity.name
считывает имя пользователя из localStorage
.
URL изображения получается из localStorage
через identity.imageUrl
.
Ура! Наше приложение теперь официально завершено. Я считаю, что мы узнали много нового о Refine и поняли некоторые обходные пути Refine, такие как использование крючков авторизации.
Заключение
К концу этой статьи вы должны хорошо понимать, как работает Refine, почему он важен в веб-приложениях, и как создать базовое веб-приложение Refine.
Это простой проект с множеством функций. Вы можете посмотреть код на GitHub или посмотреть живое представление для большей практики.
Я надеюсь, что вы найдете этот учебник таким же полезным, как и я.
Счастливого кодинга!
Полная видимость производственных приложений React
Отладка приложений React может быть сложной задачей, особенно когда пользователи сталкиваются с проблемами, которые трудно воспроизвести. Если вы заинтересованы в мониторинге и отслеживании состояния Redux, автоматическом выявлении ошибок JavaScript, отслеживании медленных сетевых запросов и времени загрузки компонентов, попробуйте LogRocket.
LogRocket — это как видеорегистратор для веб- и мобильных приложений, записывающий буквально все, что происходит в вашем React-приложении. Вместо того чтобы гадать, почему возникают проблемы, вы можете собрать данные и отчитаться о том, в каком состоянии находилось ваше приложение в момент возникновения проблемы. LogRocket также отслеживает производительность вашего приложения, предоставляя такие показатели, как загрузка процессора клиента, использование памяти клиента и многое другое.
Пакет промежуточного ПО LogRocket Redux добавляет дополнительный уровень видимости пользовательских сессий. LogRocket регистрирует все действия и состояние ваших хранилищ Redux.
Модернизируйте отладку приложений React — начните мониторинг бесплатно.