ReactJs Daily
225 subscribers
72 photos
85 links
📢 ReactJs Daily: Ваш информационный гид в мире React! 🚀

Добро пожаловать в ReactJs Dail - канал для разработчиков, увлеченных React! Здесь вы найдете все самое важное и актуальное в экосистеме React
Download Telegram
📝 Совет: Используйте Error Boundaries для защиты React-приложений

Привет, друзья! 👋

Ошибки неизбежны, особенно в больших приложениях, но важно уметь с ними справляться. Чтобы одно упавшее дерево не разрушило весь лес, используйте Error Boundaries — инструмент React для изоляции ошибок в отдельных частях интерфейса.

🔹 Зачем нужны Error Boundaries?
Иногда ошибка в одном компоненте может сломать всё приложение. Error Boundaries позволяют обработать проблему локально и показать, например, дружелюбное сообщение вместо пустого экрана.

🔹Как настроить Error Boundary?
Создайте класс-компонент с обработкой ошибок:

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError() {
return { hasError: true };
}

componentDidCatch(error, info) {
console.error('Ошибка:', error, info);
}

render() {
if (this.state.hasError) {
return <h1>Упс, что-то пошло не так 😕</h1>;
}
return this.props.children;
}
}


Теперь оберните в него часть приложения:

<ErrorBoundary>
<MyComponent />
</ErrorBoundary>


🔹 Важные нюансы
1. Error Boundaries ловят ошибки только в дочерних компонентах, включая их рендеринг и методы жизненного цикла.
2. Они не работают с ошибками в асинхронном коде и обработчиках событий.

🎯 Заключение

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

Ваши пользователи скажут вам спасибо! 😊

В React функциональные компоненты не могут быть использованы как Error Boundaries. Это связано с тем, что Error Boundaries используют методы жизненного цикла getDerivedStateFromError и componentDidCatch, которые доступны только в классовых компонентах. Конечно, существуют библиотеки, такие как react-error-boundary, которые упрощают работу с Error Boundaries и позволяют использовать их с функциональными компонентами.

ReactJs Daily | #shortinfo
1👍1
🚀 Часть 1: Знакомство с Zustand — простой и легковесный state-менеджер для React

Привет, друзья! 👋 Сегодня начинаем серию постов о Zustand, одном из самых простых и мощных инструментов для управления состоянием в React-приложениях. Это легковесная альтернатива Redux, которая идеально подходит как для небольших, так и для масштабируемых проектов.

🔹 Почему Zustand?
Zustand переводится с немецкого как "состояние". Эта библиотека минималистична, но невероятно функциональна.
Преимущества:
- Простота: минимальное API, легкое освоение.
- Легковесность: всего ~1 кБ в gzip.
- Гибкость: поддержка работы с классами, функциями и даже без React.
- Высокая производительность: оптимизирован для минимизации рендеров компонентов.

Если вы хотите управлять глобальным состоянием без сложных настроек, Zustand может стать вашим лучшим выбором!

🔹 Основы работы с Zustand
Главная идея — Zustand работает на базе store, который можно создать с помощью функции create.

Установка
npm install zustand


Пример минимального store

import create from 'zustand';

// Создаем store
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));

export default useStore;


Здесь:
- set — функция для изменения состояния.
- coun` — пример состояния.
- increment и decrement — действия (actions) для изменения count.


Подключение store в компоненте
Теперь мы можем использовать состояние в любом компоненте:
import React from 'react';
import useStore from './store';

function Counter() {
const { count, increment, decrement } = useStore();

return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}

export default Counter;


Что происходит?
1. Мы импортируем наш store.
2. Используем хук useStore для доступа к состоянию и методам.
3. Компонент автоматически перерендеривается только тогда, когда изменяются зависимости (в данном случае count).

🔹 Особенности Zustand
1. Селекторы для точечных обновлений
Вы можете оптимизировать рендеры, выбирая только нужные части состояния:
const count = useStore((state) => state.count);


Только count будет триггерить перерендер компонента.

2. Миддлвары для расширения функциональности
Zustand поддерживает миддлвары, такие как персистентность, логирование или devtools.

Пример с DevTools
import create from 'zustand';
import { devtools } from 'zustand/middleware';

const useStore = create(
devtools((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}))
);


🎯 Заключение

В первой части мы познакомились с основами Zustand. Эта библиотека проста, но невероятно функциональна.

ReactJs Daily | #pro
👍1
🚀 Организация CSS в React: Как выбрать лучший подход?

Привет, друзья! 👋 Как организовать стили, чтобы код оставался чистым и масштабируемым? Давайте разберёмся с основными подходами и их преимуществами.

🔹 CSS-модули (CSS Modules)
CSS-модули позволяют писать стили локально для каждого компонента. Имена классов генерируются автоматически, что исключает конфликты.

Пример:
import styles from './Button.module.css';

function Button() {
return <button className={styles.primary}>Кликни меня</button>;
}

/* Button.module.css */
.primary {
background-color: blue;
color: white;
}


Плюсы:
- Локальная область видимости.
- Простой синтаксис.

Минусы:
- Неудобно работать с динамическими классами.


🔹 CSS-in-JS (Emotion, Styled-Components)
Стили описываются прямо в JavaScript, часто на уровне компонента. Это позволяет легко использовать динамические значения.

Пример:
import styled from 'styled-components';

const Button = styled.button`
background-color: blue;
color: white;
&:hover {
background-color: darkblue;
}
`;

function App() {
return <Button>Кликни меня</Button>;
}



Плюсы:
- Динамическая стилизация.
- Отлично подходит для темизации.

Минусы:
- Может быть дороже в производительности.


🔹 Tailwind CSS
Утилитарный CSS-фреймворк, который позволяет быстро создавать стильные интерфейсы, используя классы.

Пример:
function Button() {
return (
<button className="bg-blue-500 text-white px-4 py-2 hover:bg-blue-700">
Кликни меня
</button>
);
}



Плюсы:
- Быстрое создание стилей без написания собственного CSS.
- Высокая гибкость.

Минусы:
- Сложность чтения, если классов слишком много.


🔹 Простой CSS

Вы можете использовать традиционный глобальный CSS, подключая стили через <link> или import.

Пример:
import './styles.css';

function Button() {
return <button className="primary">Кликни меня</button>;
}

/* styles.css */
.primary {
background-color: blue;
color: white;
}



Плюсы:
- Подходит для небольших проектов.

Минусы:
- Риск конфликтов классов.


🎯 Какой подход выбрать?

- CSS-модули: для проектов среднего масштаба.
- CSS-in-JS: если требуется динамическая стилизация или темизация.
- Tailwind CSS: для быстрого прототипирования или крупных проектов с повторяющимся дизайном.
- Простой CSS: только для самых маленьких проектов.

Выбор зависит от размера проекта, команды и предпочтений. Главное — придерживаться единого подхода в рамках одного приложения. 😊

ReactJs Daily | #begginers
🚀 Часть 2: Продвинутые техники в Zustand — миддлвары и оптимизация

Привет, друзья! 👋 Продолжаем разбираться с Zustand. В этой части рассмотрим,когда использовать shallow и подключать миддлвары.


🔹 Что такое `shallow` и как он помогает?

По умолчанию Zustand сравнивает значения, возвращаемые селектором, с помощью строгого сравнения (===). Если вы подписываетесь на сложный объект, это может приводить к ненужным ререндерам, так как объект создаётся заново при каждом изменении состояния.

shallow решает эту проблему: он выполняет поверхностное сравнение полей объектов или массивов.

Пример:
import { shallow } from 'zustand/shallow';

const { fieldA, fieldB } = useStore(
(state) => ({ fieldA: state.fieldA, fieldB: state.fieldB }),
shallow
);


Здесь:
- Компонент обновится только тогда, когда `fieldA` или `fieldB` реально изменятся.
- Если другие поля состояния изменятся, ререндера не будет.

Когда использовать shallow?
1. Если вы подписываетесь на объект с несколькими свойствами.
2. Для уменьшения ререндеров при работе с массивами или объектами.

Пример оптимизации с массивами:
const items = useStore((state) => state.items, shallow);

Если изменится структура или порядок элементов в массиве, компонент обновится. Но если массив остаётся неизменным, даже при обновлении других частей состояния, ререндер не произойдёт.

Использование shallow в паре с селекторами — мощный инструмент для повышения производительности!


🔹 Расширение через миддлвары

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

Популярные миддлвары:
1. devtools: подключение инструментов разработчика.
2. persist: сохранение состояния в localStorage.
3. immer: удобное управление неизменяемым состоянием.

Пример с devtools:
import create from 'zustand';
import { devtools } from 'zustand/middleware';

const useStore = create(
devtools((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}))
);


Использование persist:
import create from 'zustand';
import { persist } from 'zustand/middleware';

const useStore = create(
persist(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}),
{
name: 'counter-storage',
}
)
);


Теперь данные сохраняются между сессиями.


🔹 Работа с асинхронными действиями

Zustand поддерживает асинхронные операции через set.

Пример загрузки данных:
const useStore = create((set) => ({
users: [],
fetchUsers: async () => {
const response = await fetch('https://api.example.com/users');
const data = await response.json();
set({ users: data });
},
}));


В компоненте:
function UserList() {
const { users, fetchUsers } = useStore();
useEffect(() => {
fetchUsers();
}, [fetchUsers]);

return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}



🔹 Организация состояния в сложных приложениях

Когда приложение становится больше, важно правильно организовать Zustand.

Рекомендации:
1. Разделяйте store на модули
Используйте несколько независимых хранилищ для различных частей приложения (например, auth, UI, данные).

Пример:
const useAuthStore = create((set) => ({
isAuthenticated: false,
login: () => set({ isAuthenticated: true }),
}));

const useUIStore = create((set) => ({
theme: 'light',
toggleTheme: () =>
set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })),
}));


2. Используйте context для передачи store
Для улучшения читабельности в больших приложениях.


🎯 Заключение

Zustand — это не только простой state-менеджер, но и мощный инструмент для сложных приложений. Используя селекторы, миддлвары и асинхронные действия, вы можете оптимизировать производительность и упростить работу с состоянием.

ReactJs Daily | #pro
🔥2
🚀 Как использовать useRef в React?

Привет, друзья! 👋 Сегодня поговорим о хуке `useRef`, который открывает массу возможностей для работы с DOM, сохранения данных между рендерами и улучшения производительности.

🔹 Что такое `useRef`?

useRef — это React-хук, который возвращает объект с единственным свойством current. Этот объект сохраняется между рендерами, но изменение его значения не вызывает перерендер компонента.


🔹 Основные сценарии использования

1. Доступ к DOM-элементу
Часто используется для управления элементами напрямую (например, установка фокуса).

import React, { useRef } from 'react';

function InputFocus() {
const inputRef = useRef(null);

const handleFocus = () => {
inputRef.current?.focus(); // Устанавливаем фокус на input
};

return (
<div>
<input ref={inputRef} type="text" placeholder="Введите текст" />
<button onClick={handleFocus}>Фокус на поле ввода</button>
</div>
);
}


2. Сохранение значений между рендерами
useRef отлично подходит для хранения данных, которые не должны теряться между рендерами, но не требуют обновления UI.

import React, { useRef, useState } from 'react';

function Counter() {
const renderCount = useRef(0); // Сохраняем количество рендеров
const [count, setCount] = useState(0);

renderCount.current += 1;

return (
<div>
<p>Счетчик: {count}</p>
<p>Количество рендеров: {renderCount.current}</p>
<button onClick={() => setCount(count + 1)}>Увеличить</button>
</div>
);
}


3. Улучшение производительности через сохранение данных
Вы можете использовать useRef для сохранения данных, которые не должны пересоздаваться при каждом рендере, например, таймеры или идентификаторы.

import React, { useRef, useEffect } from 'react';

function Timer() {
const timerId = useRef(null);

useEffect(() => {
timerId.current = setInterval(() => {
console.log('Таймер работает!');
}, 1000);

return () => {
if (timerId.current) clearInterval(timerId.current); // Очищаем таймер
};
}, []);

return <div>Таймер запущен. Проверьте консоль!</div>;
}



🔹 Важные моменты

1. `useRef` не вызывает ререндер компонента.
Изменение ref.current не заставляет React обновлять компонент, это просто ссылка.

2. Подходит для долгосрочных данных.
Храните данные, которые не зависят от рендеров, например, DOM-узлы, идентификаторы или счётчики.

3. Не используйте `useRef` как state.
Если вы хотите обновлять UI при изменении значения, лучше использовать useState.


🎯 Заключение

useRef — мощный инструмент, который помогает эффективно работать с DOM и сохранять значения между рендерами. Используйте его, когда вам нужно управлять DOM-узлами, хранить "незаметные" данные или улучшить производительность.

ReactJs Daily | #begginers
👍2
🚀 Введение в GraphQL: Эффективный способ работы с API

Привет, друзья! 👋 Обсудим GraphQL, современный инструмент для работы с API, который меняет подход к запросам данных. Это мощная альтернатива REST, предоставляющая разработчикам больше гибкости и удобства.

🔹 Что такое GraphQL?

GraphQL — это язык запросов и среда выполнения для получения данных. Разработан Facebook в 2015 году, чтобы упростить работу с API.

Вместо фиксированных эндпоинтов (как в REST) вы пишете запросы, которые возвращают только необходимые данные.

🔹 Основные преимущества GraphQL

1. Запрашивайте только нужные данные
GraphQL позволяет точно указать, какие данные вам нужны, избегая перегрузки избыточной информацией.

Пример:
query {
user(id: "1") {
id
name
email
}
}


Ответ:
{
"data": {
"user": {
"id": "1",
"name": "Alice",
"email": "alice@example.com"
}
}
}


2. Один запрос — множество ресурсов
GraphQL позволяет получать данные из разных источников за один запрос.

3. Гибкость в разработке
Изменение структуры данных не требует переписывания запросов, если нужные поля остаются доступными.

4. Сильная типизация
Схема API описывает данные, их типы и связи. Это упрощает работу с большими командами.

🔹 Как это работает?

1. Schema: описывает типы данных и их связи.
type User {
id: ID!
name: String!
email: String!
}

type Query {
user(id: ID!): User
}


2. Resolvers: функции, которые выполняют запросы.
const resolvers = {
Query: {
user: (_, { id }) => getUserById(id),
},
};


3. Запросы: клиенты пишут их для получения данных.

🔹 GraphQL и React

GraphQL отлично работает с React благодаря библиотекам, таким как Apollo Client.

Установка Apollo Client:
npm install @apollo/client graphql


Пример запроса:
import { useQuery, gql } from '@apollo/client';

const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;

function User({ id }) {
const { loading, error, data } = useQuery(GET_USER, { variables: { id } });

if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;

return (
<div>
<h1>{data.user.name}</h1>
<p>{data.user.email}</p>
</div>
);
}


🎯 Заключение

GraphQL — это инструмент, который упрощает работу с API, повышает производительность разработки и даёт больше контроля над данными. Он особенно полезен для сложных приложений с множеством взаимосвязанных ресурсов.

Используете ли вы GraphQL в своих проектах? Делитесь опытом в комментариях! 😊

ReactJs Daily | #pro
🔥3
🚀 Higher-Order Components (HOC) в React: Паттерн для повторного использования логики

Привет, друзья! 👋 Сегодня поговорим о Higher-Order Components (HOC) — одном из популярных паттернов в React, который помогает повторно использовать логику между компонентами.

🔹 Что такое HOC?

HOC (компонент высшего порядка) — это функция, которая принимает компонент и возвращает новый компонент с добавленной функциональностью.

HOC ≠ обычный компонент. Это скорее обёртка, которая расширяет функционал ваших компонентов.

Синтаксис:
const withExtraProps = (WrappedComponent) => {
return (props) => {
// Добавляем новые пропсы или логику
const extraProps = { additional: 'value' };
return <WrappedComponent {...props} {...extraProps} />;
};
};


🔹 Когда использовать HOC?

HOC применяется, когда нужно:
1. Повторное использование логики между несколькими компонентами.
2. Оборачивать компонент в дополнительную функциональность, например, авторизация, логирование или обработка данных.
3. Добавить новые пропсы или состояния.

Пример: HOC для проверки авторизации.

🔹 Пример HOC

Задача: Реализовать HOC для отображения содержимого только для авторизованных пользователей.

import React from 'react';

// HOC для проверки авторизации
const withAuth = (WrappedComponent) => {
return (props) => {
const isAuthenticated = props.isAuthenticated; // Получаем пропс

if (!isAuthenticated) {
return <div>Доступ запрещён. Пожалуйста, войдите в систему.</div>;
}

return <WrappedComponent {...props} />;
};
};

// Пример компонента
const UserProfile = (props) => {
return <div>Привет, {props.name}! Это твой профиль.</div>;
};

// Оборачиваем компонент
const ProtectedUserProfile = withAuth(UserProfile);

// Использование
export default function App() {
return (
<div>
<ProtectedUserProfile isAuthenticated={false} name="Алексей" />
</div>
);
}



Результат: Если пользователь не авторизован, вместо компонента UserProfile отобразится сообщение "Доступ запрещён".

🔹 Важные аспекты при работе с HOC

1. Передача пропсов
HOC должен передавать все пропсы внутрь оборачиваемого компонента, чтобы он оставался гибким:

<WrappedComponent {...props} />


2. Декларативное имя
Придумайте читаемое имя для вашего HOC, например, withAuth, withLogger.

3. Не переусложняйте
HOC может сделать код сложнее для понимания. Если логику можно вынести в кастомные хуки — выбирайте их.

4. Не мутируйте оборачиваемый компонент
HOC не должен изменять оригинальный компонент, а только оборачивать его.

🔹 Когда НЕ использовать HOC

Сегодня многие задачи, которые решались через HOC, проще выполнять с помощью:
- Custom Hooks для повторного использования логики.
- Context API для глобального состояния.

HOC остаётся актуальным, но его популярность снижается в пользу более простых решений.

🎯 Заключение

Higher-Order Components — мощный инструмент, если вы хотите добавить функционал к компонентам, сохраняя их чистоту и переиспользуемость. Но помните, что HOC — не единственный способ повторного использования логики, и в некоторых случаях кастомные хуки могут быть лучшим выбором 😊

ReactJs Daily | #begginers
👍1🆒1
🚀 Основы тестирования ReactJS: как и зачем тестировать компоненты?

Привет, друзья! 👋 В этом посте мы поговорим о том, почему тесты важны, как они помогают, и какие инструменты вам понадобятся для написания эффективных тестов.

🔹 Зачем тестировать React-приложения?

Тестирование — важный процесс разработки, который помогает вам:
1. Убедиться, что ваш код работает правильно и не ломает функционал при изменениях.
2. Предотвратить баги и минимизировать их появление на более поздних этапах разработки.
3. Обеспечить стабильность приложения, что особенно важно при добавлении нового функционала.

Но помимо этого тесты помогают вам думать о логике компонентов и улучшать их архитектуру!

🔹 Основные типы тестов в React

1. Юнит-тесты (Unit tests): Проверяют функциональность отдельных функций и компонентов.
2. Интеграционные тесты (Integration tests): Проверяют, как несколько частей системы взаимодействуют друг с другом.
3. Тесты интерфейса (UI tests): Проверяют, как компоненты взаимодействуют с пользователем (например, как кнопки работают, что отображается на экране).

🔹 Какие инструменты использовать?

1. Jest — это тестовый фреймворк, который работает из коробки с React. Он удобен, имеет поддержку моков, и легко интегрируется с другими библиотеками.
2. React Testing Library — библиотека для тестирования компонентов React, ориентированная на поведение пользователей, а не на реализацию. Это помогает делать тесты более близкими к реальному использованию компонента.
3. Jest-DOM — дополнение для Jest, которое добавляет полезные матчеры для проверки наличия элементов, их текста и других свойств в DOM.

🔹 Как начать?

1. Установка необходимых зависимостей
Сначала установим Jest и React Testing Library. Откройте терминал и выполните команду:
npm install --save-dev jest @testing-library/react @testing-library/jest-dom


2. Пример простого теста

Предположим, у нас есть компонент Counter, который увеличивает счётчик на 1 при каждом нажатии кнопки.

// Counter.js
import React, { useState } from 'react';

const Counter = () => {
const [count, setCount] = useState(0);

return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};

export default Counter;


Теперь напишем тест для этого компонента:

// Counter.test.js
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';

test('увеличение счётчика при нажатии кнопки', () => {
render(<Counter />); // Рендерим компонент

expect(screen.getByText(/Count:/).textContent).toBe('Count: 0');

const button = screen.getByText('Increment');
fireEvent.click(button);

expect(screen.getByText(/Count:/).textContent).toBe('Count: 1');
});


Что происходит:
1. Мы рендерим компонент с помощью render.
2. Используем screen.getByText для поиска текста на экране.
3. Симулируем нажатие кнопки с помощью fireEvent.
4. Проверяем, что счётчик увеличился.

🔹 Основные методы React Testing Library

- render() — рендерит компонент в виртуальный DOM для тестирования.
- screen — объект, который предоставляет доступ к элементам на экране (например, через screen.getByText или screen.getByRole).
- fireEvent — используется для симуляции событий, таких как клик или ввод текста.
- waitFor — помогает дождаться выполнения асинхронных операций, например, загрузки данных.

🔹 Практические советы

1. Тестируйте поведение, а не реализацию. Не проверяйте, что именно делает компонент внутри (например, функции или методы), а смотрите, как он влияет на интерфейс.
2. Избегайте сложных моков. Если возможно, тестируйте компоненты с реальными зависимостями, а не подменяйте их через моки, чтобы тесты были ближе к реальности.
3. Не забывайте про асинхронные тесты. Если ваш компонент работает с асинхронными запросами, используйте waitFor или findBy для правильной работы с промисами и API.

🎯 Заключение

Jest и React Testing Library — это отличный способ убедиться, что ваше приложение работает корректно и стабильно.

ReactJs Daily | #testing
🔥3👍2🆒2
🚀 Интерфейсы в TypeScript: почему они важны и как использовать?

Привет, друзья! 👋 Сегодня поговорим об одном из самых мощных инструментов TypeScript — интерфейсах. Если вы хотите организовать код, сделать его читаемым и удобным для поддержки, интерфейсы — ваш лучший помощник.

🔹 Что такое интерфейс?

Интерфейс — это своего рода "договор", определяющий структуру данных. Он устанавливает требования, которым должны соответствовать объект или класс.

🔹 Простой пример

Допустим, вы работаете с данными пользователя:
interface User {
id: number;
name: string;
email: string;
}

const user: User = {
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
};


Здесь интерфейс User:
- Определяет, что объект должен иметь свойства id, name и email.
- Гарантирует, что типы данных будут соответствовать описанным.

🔹 Зачем использовать интерфейсы?

1. Понятность: сразу видно, какие свойства ожидаются у объекта.
2. Типобезопасность: ошибки в коде обнаруживаются на этапе компиляции.
3. Повторное использование: интерфейсы можно использовать в нескольких местах.
4. Читаемость: код становится проще для других разработчиков.

🔹 Опциональные свойства

Не все свойства обязательно должны быть указаны. Добавим "?" перед именем свойства:
interface User {
id: number;
name: string;
email?: string; // Опциональное свойство
}

const userWithoutEmail: User = {
id: 2,
name: 'Jane Smith',
};


🔹 Комбинирование интерфейсов

Интерфейсы можно расширять с помощью ключевого слова extends:
interface User {
id: number;
name: string;
}

interface Admin extends User {
role: string;
}

const admin: Admin = {
id: 1,
name: 'Admin User',
role: 'Super Admin',
};


Это удобно, если у вас есть общая структура, которую нужно доработать.

🔹 Использование интерфейсов с компонентами React

Интерфейсы прекрасно работают с пропсами в компонентах:
interface ButtonProps {
label: string;
onClick: () => void;
}

const Button: React.FC<ButtonProps> = ({ label, onClick }) => (
<button onClick={onClick}>{label}</button>
);


Теперь TypeScript подскажет, какие пропсы требуются для компонента, и вы избежите ошибок.

🎯 Заключение

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

ReactJs Daily | #begginers
📝 useLayoutEffect в React: когда и зачем использовать?

useLayoutEffect — это хук, который запускается синхронно после всех изменений в DOM. В отличие от useEffect, он срабатывает до того, как браузер отрисует кадр, что делает его полезным для измерения и изменения DOM.

🔹 Как работает `useLayoutEffect`?

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

🔹 Пример использования

Представим, что нужно динамически прокрутить элемент в зависимости от его размеров:
import { useLayoutEffect, useRef } from "react";

function ScrollToBottom() {
const containerRef = useRef(null);

useLayoutEffect(() => {
const container = containerRef.current;
if (container) {
container.scrollTop = container.scrollHeight; // Прокрутка до конца
}
}, []); // Пустой массив зависимостей — эффект выполняется один раз

return (
<div
ref={containerRef}
style={{ height: "200px", overflow: "auto", border: "1px solid black" }}
>
<p>Содержимое...</p>
<p>Много текста...</p>
</div>
);
}


В этом примере useLayoutEffect гарантирует, что прокрутка произойдёт *до* отрисовки обновлённого интерфейса.

🔹 Когда использовать?

1. Измерение DOM-элементов: ширина, высота, позиция.
2. Синхронные изменения DOM: изменение стилей или положения элементов.
3. Сложные анимации: точное управление рендерингом.

🔹 Важное отличие от `useEffect`

- useEffect выполняется асинхронно, после отрисовки.
- useLayoutEffect блокирует отрисовку, поэтому может замедлить загрузку страницы при избыточном использовании.


🎯 Заключение

Используйте useLayoutEffect только тогда, когда useEffect не подходит, например, если вы видите "мерцания" в интерфейсе из-за запоздалых измерений или изменений DOM.

Простые задачи? Лучше useEffect.
Сложные изменения DOM? Берите useLayoutEffect.

ReactJs Daily | #shortinfo
🚀 Тестирование компонентов React: Основные подходы

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

🔹 Проверка отображения элементов (DOM)

Основная задача тестирования DOM — убедиться, что нужные элементы отображаются на странице.

Пример:
import { render, screen } from "@testing-library/react";
import MyComponent from "./MyComponent";

test("renders the title", () => {
render(<MyComponent />);
const title = screen.getByText(/Hello, World!/i);
expect(title).toBeInTheDocument();
});


Совет: Используйте методы getBy*, queryBy* и findBy* в зависимости от контекста:
- getBy* — для синхронного поиска.
- findBy* — для асинхронных тестов.
- queryBy* — когда элемент может отсутствовать.

🔹 Тестирование пропсов и состояния (state)

Для компонентов с состоянием или пропсами важно проверять, как они меняются и влияют на поведение.

Пример:
import { render, screen } from "@testing-library/react";
import MyButton from "./MyButton";

test("renders button with the correct label", () => {
render(<MyButton label="Click me" />);
const button = screen.getByText(/Click me/i);
expect(button).toBeInTheDocument();
});


Совет: Используйте мок-пропсы для проверки поведения компонента.

🔹 Работа с событиями: клик, ввод текста, прокрутка

Проверяйте, как компоненты реагируют на пользовательские действия: клики, ввод текста или другие события.

Пример:
import { render, screen, fireEvent } from "@testing-library/react";
import Counter from "./Counter";

test("increments counter on button click", () => {
render(<Counter />);
const button = screen.getByRole("button", { name: /increment/i });
fireEvent.click(button);
expect(screen.getByText("Count: 1")).toBeInTheDocument();
});


Совет: Вместо fireEvent для сложных взаимодействий используйте user-event — это ближе к реальным сценариям.

🔹 Тестирование условного рендера

Компоненты часто рендерят элементы в зависимости от условий. Убедитесь, что все сценарии работают корректно.

Пример:
import { render, screen } from "@testing-library/react";
import ConditionalComponent from "./ConditionalComponent";

test("renders message when condition is true", () => {
render(<ConditionalComponent show={true} />);
expect(screen.getByText(/Condition is true/i)).toBeInTheDocument();
});

test("does not render message when condition is false", () => {
render(<ConditionalComponent show={false} />);
expect(screen.queryByText(/Condition is true/i)).toBeNull();
});


Совет: Покрывайте как положительные, так и отрицательные сценарии.

🔹 Снапшот-тестирование с Jest

Снапшот-тесты проверяют, что внешний вид компонента остается неизменным. Это удобно для UI-компонентов.

Пример:
import renderer from "react-test-renderer";
import MyComponent from "./MyComponent";

test("matches the snapshot", () => {
const tree = renderer.create(<MyComponent />).toJSON();
expect(tree).toMatchSnapshot();
});


Совет: Регулярно обновляйте снапшоты, если изменения в интерфейсе ожидаемы.

🎯 Заключение

Тестирование React-компонентов помогает гарантировать их корректную работу:
1. Проверяйте, что нужные элементы отображаются.
2. Убедитесь в правильности работы пропсов и состояния.
3. Тестируйте пользовательские действия.
4. Покрывайте сценарии условного рендера.
5. Используйте снапшоты для стабильности UI.

ReactJs Daily | #testing
🚀 Основы Next.js: Погружение в современный фреймворк для React

Привет! Сегодня разберём, что такое Next.js, почему его выбирают разработчики, как настроить проект и чем он лучше стандартного Create React App. 🚀

🔹 Что такое Next.js?

Next.js — это фреймворк на основе React, который добавляет мощные возможности: серверный рендеринг (SSR), статическую генерацию (SSG), оптимизацию производительности и удобные инструменты для разработки.

Почему он популярен?
1. SEO: SSR и SSG делают страницы индексируемыми поисковыми системами.
2. Производительность: оптимизация загрузки ресурсов, встроенная поддержка ленивая загрузки изображений.
3. Простота: минимальная настройка для работы с маршрутизацией, API и стилями.
4. Гибкость: возможность использовать как серверный, так и статический рендеринг.
5. Удобство: готовая интеграция с Vercel для деплоя.

🔹 Установка и настройка проекта

Начать работать с Next.js просто:

Установка проекта:
npx create-next-app@latest my-nextjs-app
cd my-nextjs-app
npm run dev



После этого проект будет доступен по адресу [http://localhost:3000](http://localhost:3000).

Структура стандартного проекта:
- pages/ — папка для маршрутов и страниц.
- public/ — статические файлы (изображения, шрифты и т.д.).
- styles/ — глобальные и модульные стили.

🔹 Архитектура папок

1. `pages/`:
- Каждая .js или .tsx файл в этой папке автоматически становится маршрутом.
- Например, файл about.js доступен по /about.
- Поддерживается динамическая маршрутизация:

// pages/post/[id].js
import { useRouter } from 'next/router';

export default function Post() {
const { query } = useRouter();
return <div>Post ID: {query.id}</div>;
}



2. `public/`:
- Хранит статические ресурсы, доступные напрямую.
- Например, файл logo.png в этой папке будет доступен по /logo.png.

3. `styles/`:
- Хранит глобальные стили (globals.css) и модульные стили (Component.module.css).
- CSS-модули позволяют изолировать стили для каждого компонента.

🔹 Создание страниц

Next.js использует файловую маршрутизацию: структура файлов в папке pages/ соответствует URL-адресам.

Пример простой страницы:
// pages/about.js
export default function About() {
return <h1>About Page</h1>;
}


После этого страница будет доступна по адресу /about.

Динамические маршруты:
// pages/product/[id].js
import { useRouter } from 'next/router';

export default function Product() {
const { query } = useRouter();
return <h1>Product ID: {query.id}</h1>;
}


Этот подход позволяет создавать маршруты для страниц с параметрами, например, /product/123.

🔹 Next.js vs Create React App

Преимущества Next.js:
1. Серверный рендеринг (SSR): улучшает SEO и время загрузки страниц.
2. Статическая генерация (SSG): рендерит HTML на этапе сборки.
3. API-маршруты: возможность создавать серверные эндпоинты прямо в проекте.
4. Оптимизация изображений: компонент <Image> автоматически обрабатывает загрузку и размеры.
5. Встроенная маршрутизация: не нужно подключать дополнительные библиотеки, как в Create React App.

🎯 Заключение

Next.js — это мощный инструмент, который добавляет React приложению функциональности из коробки: рендеринг на сервере, генерацию статических страниц и многое другое.

ReactJs Daily | #nextjs
3👍2
🚀 Storybook: Создаём изолированную среду для разработки компонентов

Привет, друзья! 👋 Поговорим о Storybook, инструменте, который помогает создавать, тестировать и документировать UI-компоненты в изолированной среде.

Если вы хотите улучшить процесс разработки компонентов, сделать его более удобным и организованным, Storybook — идеальное решение.

🔹 Что такое Storybook?

Storybook — это инструмент для разработки компонентов в изоляции.
- Он позволяет сосредоточиться на создании и настройке компонентов без влияния остального приложения.
- Это отличная платформа для документирования вашего UI.

🔹 Почему стоит использовать Storybook?

1. Изолированная разработка: создавайте и тестируйте компоненты независимо от основного приложения.
2. Документация: Storybook автоматически создаёт интерактивную документацию, где можно просматривать и взаимодействовать с компонентами.
3. Тестирование: удобно тестировать edge-cases и различные состояния компонентов (например, с разными пропсами).
4. Удобство для команды: команда дизайнеров, разработчиков и тестировщиков получает доступ к библиотеке компонентов.

🔹 Установка и настройка

1. Установка Storybook
Добавьте Storybook в свой проект:
npx storybook@latest init


2. Запуск Storybook
После установки запустите сервер:
npm run storybook

Он откроется в браузере по умолчанию (обычно на http://localhost:6006).

🔹 Как писать "сториз"?

Каждый компонент в Storybook представлен в виде *story* — это сценарий, описывающий, как компонент выглядит в определённых состояниях.

Пример компонента и его сториз

Button.js
import React from 'react';

const Button = ({ label, onClick }) => (
<button onClick={onClick}>{label}</button>
);

export default Button;


Button.stories.js
import React from 'react';
import Button from './Button';

export default {
title: 'Example/Button', // Название компонента
component: Button, // Компонент
};

const Template = (args) => <Button {...args} />;

export const Primary = Template.bind({});
Primary.args = {
label: 'Primary Button',
};

export const Secondary = Template.bind({});
Secondary.args = {
label: 'Secondary Button',
};


Что здесь происходит?
- `title`: путь, где компонент будет отображаться в интерфейсе Storybook.
- `Template`: базовый шаблон для сториз.
- `args`: пропсы, которые вы передаёте компоненту.

Теперь в Storybook вы увидите кнопку с двумя состояниями: Primary и Secondary.

🔹 Расширение возможностей Storybook

1. Addons:
Storybook поддерживает плагины для улучшения функциональности. Популярные аддоны:
- Controls: интерактивная настройка пропсов.
- Docs: автоматическая генерация документации.
- Actions: отслеживание вызовов событий.

Установить аддон можно так:
npm install @storybook/addon-controls


2. Тестирование компонентов:
Storybook поддерживает интеграцию с тестовыми библиотеками, например, Jest или Chromatic, для визуального тестирования компонентов.

🔹 Преимущества для команды

- Разработчики: легко проверять и дорабатывать компоненты.
- Дизайнеры: получают визуальную библиотеку UI.
- Тестировщики: могут видеть и тестировать компоненты в изоляции.

🎯 Заключение

Storybook — это мощный инструмент, который ускоряет разработку и улучшает качество UI. С ним вы сможете не только упорядочить свою библиотеку компонентов, но и наладить эффективное взаимодействие в команде.

ReactJs Daily | #pro
👍2🤔1
🚀 Порталы и модальные окна в React: универсальное решение для вашего UI

Привет, друзья! 👋 Сегодня поговорим о порталах в React и их применении для создания универсальных компонентов модальных окон. Это важный инструмент для работы с элементами, которые должны отображаться вне DOM-иерархии родительского компонента.

🔹 Что такое порталы в React?

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

Создаются с помощью метода ReactDOM.createPortal.
Пример:
ReactDOM.createPortal(child, container)


- child — React-элемент, который нужно отобразить.
- container — DOM-узел, куда этот элемент будет вставлен.

🔹 Почему это важно для модальных окон?

Модальные окна часто должны:
1. Перекрывать всё приложение.
2. Не зависеть от родительских стилей.
3. Быть легко доступными для управления.

Порталы позволяют рендерить модальные окна в корневой DOM-узел, например, <div id="modal-root">.

🔹 Создание универсального компонента модального окна

Шаг 1. Добавьте корневой элемент в HTML:
<div id="modal-root"></div>


Шаг 2. Создайте компонент Modal:
import React from 'react';
import ReactDOM from 'react-dom';

const Modal = ({ isOpen, onClose, children }) => {
if (!isOpen) return null;

return ReactDOM.createPortal(
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<button className="modal-close" onClick={onClose}>×</button>
{children}
</div>
</div>,
document.getElementById('modal-root')
);
};

export default Modal;


Что здесь происходит?
1. Условный рендеринг: если окно закрыто, ничего не возвращается.
2. Портал: модальное окно рендерится в #modal-root.
3. Закрытие по клику: окно закрывается при клике на фон или кнопку.

🔹 Использование компонента Modal

Пример в приложении:
import React, { useState } from 'react';
import Modal from './Modal';

function App() {
const [isModalOpen, setModalOpen] = useState(false);

return (
<div>
<button onClick={() => setModalOpen(true)}>Открыть модальное окно</button>
<Modal isOpen={isModalOpen} onClose={() => setModalOpen(false)}>
<h1>большой привет от ReactJs Daily!</h1>
<p>Подпишись на канал)</p>
</Modal>
</div>
);
}

export default App;


🔹 Преимущества подхода

1. Изоляция: модальное окно не зависит от стилей родителя.
2. Гибкость: компонент легко переиспользовать.
3. Чистота DOM: модальное окно рендерится в отдельный контейнер, упрощая структуру приложения.

🎯 Заключение

Порталы в React — это мощный инструмент для работы с элементами вне стандартной DOM-иерархии. Используйте их, чтобы создавать удобные и универсальные модальные окна, которые будут легко интегрироваться в любое приложение.

ReactJs Daily | #begginers
👍1
🚀 Тестирование Redux: Actions, Reducers и подключение mock-хранилища

Привет! Сегодня разберём, как правильно тестировать actions, reducers и компоненты, подключённые к Redux. Эти знания помогут вам убедиться, что ваше состояние и логика работают корректно.

🔹 Тестирование reducers

Reducer — это чистая функция. Она принимает текущее состояние и action, возвращая новое состояние.

Структура теста
1. Определите начальное состояние.
2. Передайте в reducer action и проверьте результат.

Пример:
import { counterReducer } from './counterSlice';

describe('counterReducer', () => {
it('должен увеличивать значение', () => {
const initialState = { count: 0 };
const action = { type: 'counter/increment' };

const result = counterReducer(initialState, action);

expect(result).toEqual({ count: 1 });
});

it('должен уменьшать значение', () => {
const initialState = { count: 2 };
const action = { type: 'counter/decrement' };

const result = counterReducer(initialState, action);

expect(result).toEqual({ count: 1 });
});
});


Почему это важно?
- Убедитесь, что ваш reducer возвращает корректное состояние для каждого action.
- Проверка edge-кейсов (например, неожиданных значений).

🔹 Тестирование actions

Actions сами по себе тестировать несложно. Однако для thunk или асинхронных actions вам понадобятся моки.

Пример: Тестирование синхронных actions
import { increment, decrement } from './counterSlice';

describe('actions', () => {
it('increment должен возвращать правильный action', () => {
expect(increment()).toEqual({ type: 'counter/increment' });
});

it('decrement должен возвращать правильный action', () => {
expect(decrement()).toEqual({ type: 'counter/decrement' });
});
});


Пример: Тестирование асинхронных actions (с помощью redux-thunk)
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { fetchData } from './dataActions';
import { fetchDataSuccess } from './dataSlice';

const mockStore = configureMockStore([thunk]);

describe('async actions', () => {
it('должен диспатчить fetchDataSuccess после успешного API-запроса', async () => {
const store = mockStore({});
const mockResponse = { data: 'test' };

// Мокаем fetch
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve(mockResponse),
})
);

await store.dispatch(fetchData());

const actions = store.getActions();
expect(actions[0]).toEqual(fetchDataSuccess(mockResponse));
});
});


🔹 Подключение mock-хранилища для компонентов

Для тестирования компонентов, использующих Redux, используйте mock-store или обёртку Provider с тестовым хранилищем.

Пример: Тестирование компонента с Provider
import React from 'react';
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import Counter from './Counter';

const mockStore = configureMockStore([]);

describe('Counter component', () => {
it('должен отображать начальное значение', () => {
const store = mockStore({ counter: { count: 0 } });

const { getByText } = render(
<Provider store={store}>
<Counter />
</Provider>
);

expect(getByText('Count: 0')).toBeInTheDocument();
});
});


🔹 Практические советы

1. Тестируйте reducers отдельно: Это чистые функции, их тестировать проще всего.
2. Используйте моки для API-запросов: jest.fn() или библиотеки, такие как msw.
3. Тестируйте взаимодействие компонентов с Redux: С помощью mock-store или настоящего Redux-хранилища в тестовой среде.

🎯 Заключение

Тестирование Redux — важная часть создания стабильных и надёжных приложений. Начните с проверки reducers, затем переходите к actions, а после - к тестированию компонентов с использованием mock-хранилища.

ReactJs Daily | #testing
👍1
🚀 Фишки Create React App: что вы могли не знать

Create React App (CRA) делает создание React-приложений простым и удобным. Однако за этим "простым стартом" скрываются мощные функции, которые часто остаются незамеченными. Давайте разберёмся, какие фишки CRA могут ускорить вашу работу и сделать её комфортнее.

🔹 1. Плагин TypeScript из коробки

Хотите использовать TypeScript? CRA полностью поддерживает его!
При создании нового проекта достаточно добавить флаг:
npx create-react-app my-app --template typescript


И вы получите готовую настройку для работы с TypeScript без дополнительной конфигурации.

🔹 2. Поддержка CSS и CSS Modules

CRA поддерживает как обычные CSS-стили, так и модульные стили (CSS Modules). Модульные стили позволяют изолировать CSS для каждого компонента.
Пример:
import styles from './Button.module.css';

function Button() {
return <button className={styles.primary}>Click me</button>;
}


🔹 3. Работа с изображениями и файлами

Вы можете импортировать изображения и файлы прямо в ваш JavaScript-код:
import logo from './logo.svg';

function App() {
return <img src={logo} alt="Logo" />;
}

CRA автоматически оптимизирует изображения при сборке для продакшена.

🔹 4. Hot Module Replacement (HMR)

При разработке изменения в вашем коде моментально применяются без перезагрузки страницы. Это называется горячая перезагрузка модулей, и CRA поддерживает её из коробки.

🔹 5. Автоматическая оптимизация для продакшена

Команда npm run build создаёт готовый к деплою проект с минимизацией файлов, оптимизацией CSS, и удалением ненужного кода.

🔹 6. Экспериментальные функции через `.env`

CRA позволяет использовать переменные окружения для настройки вашего приложения. Добавьте файл .env и укажите там переменные, например:
REACT_APP_API_URL=https://api.example.com


В коде они доступны через process.env.REACT_APP_API_URL.

🔹 7. Подключение к React Developer Tools

CRA предустанавливает все настройки для использования с React Developer Tools, позволяя вам отлаживать состояние компонентов прямо в браузере.

🔹 8. Легкое тестирование с Jest

В вашем проекте сразу настроен Jest, что позволяет писать тесты с первого дня. Просто добавьте тестовые файлы рядом с вашими компонентами, и запускайте:
npm test


🔹 9. Поддержка ESLint

CRA автоматически интегрирует ESLint для анализа вашего кода. Он не только помогает соблюдать стандарты, но и предоставляет полезные советы в консоли разработки.

🔹 10. Eject для кастомизации

Если вам нужно больше контроля над настройками (например, Webpack, Babel), вы можете выполнить npm run eject. Это сделает конфигурацию доступной для редактирования, но будьте осторожны: отменить eject невозможно!

🎯 Заключение

Create React App — это не просто инструмент для быстрого старта. Он предоставляет множество мощных функций, которые делают разработку удобной и эффективной. Используйте эти фишки, чтобы раскрыть весь потенциал CRA!

ReactJs Daily | #begginers
👍2🔥1
🚀 Отмена запросов в React: как правильно работать с асинхронностью

Работа с API — неотъемлемая часть разработки React-приложений. Но что делать, если запрос больше не нужен? Например, пользователь ушёл со страницы до того, как запрос завершился. Вот где возникает необходимость отмены запросов.

🔹 Почему это важно?

1. Избежание утечек памяти. Незакрытые запросы могут потреблять ресурсы.
2. Исключение ошибок. Попытка обновить состояние размонтированного компонента приведёт к ошибке в консоли.
3. Оптимизация производительности. Меньше ненужных запросов — лучше UX.

🔹 Как отменить запросы?

1. Используем AbortController
Встроенный API AbortController позволяет отменять запросы.

Пример:

import React, { useEffect } from 'react';

function App() {
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;

fetch('https://api.example.com/posts', { signal })
.then((response) => response.json())
.then((data) => console.log(data))
.catch((err) => {
if (err.name === 'AbortError') {
console.log('Запрос отменён');
} else {
console.error('Ошибка:', err);
}
});

return () => {
controller.abort(); // Отменяем запрос при размонтировании
};
}, []);

return <h1>Отмена запросов с помощью AbortController</h1>;
}

export default App;

Что здесь происходит?

- Мы создаём экземпляр AbortController.
- Передаём его signal в запрос fetch.
- При размонтировании компонента вызываем abort(), чтобы отменить запрос.

2. Используем библиотеки (например, Axios)
Некоторые библиотеки, такие как Axios, имеют встроенную поддержку отмены запросов.

Пример с Axios:

import React, { useEffect } from 'react';
import axios from 'axios';

function App() {
useEffect(() => {
const controller = new AbortController();

axios
.get('https://api.example.com/posts', {
signal: controller.signal,
})
.then((response) => console.log(response.data))
.catch((err) => {
if (axios.isCancel(err)) {
console.log('Запрос отменён');
} else {
console.error('Ошибка:', err);
}
});

return () => {
controller.abort();
};
}, []);

return <h1>Отмена запросов с Axios</h1>;
}

export default App;

3. Обработка асинхронных эффектов с помощью флагов
Если вы не используете библиотеки или AbortController, можно обойтись флагами, хотя это менее элегантно.

Пример с флагом:

import React, { useEffect, useState } from 'react';

function App() {
const [data, setData] = useState(null);

useEffect(() => {
let isMounted = true;

fetch('https://api.example.com/posts')
.then((response) => response.json())
.then((data) => {
if (isMounted) {
setData(data);
}
});

return () => {
isMounted = false; // Флаг при размонтировании
};
}, []);

return <div>{data ? <h1>Данные загружены</h1> : <h1>Загрузка...</h1>}</div>;
}

export default App;

🔹 Рекомендации

1. Используйте AbortController для современных браузеров.
2. Если используете Axios или другую библиотеку — проверьте, поддерживает ли она отмену запросов.
3. Не забывайте очищать эффекты с асинхронным кодом, чтобы избежать утечек памяти.
4. Покрывайте такие сценарии тестами.

🎯 Заключение

Отмена запросов — это важный аспект работы с асинхронностью в React. Она улучшает производительность и стабильность приложения 😊

ReactJs Daily | #begginers
👍1🔥1
🚀 Тестирование API и эффектов в React: простые шаги для качественного кода

Тестирование API-запросов и эффектов, таких как useEffect, — это важная часть разработки, особенно в компонентах, которые взаимодействуют с сервером. Давайте разберём основные подходы и инструменты, которые помогут вам писать надёжные тесты.

🔹 Почему это важно?

Компоненты, работающие с API, часто становятся источником ошибок: проблемы с сетью, некорректные данные или неожиданные состояния. Тестирование помогает:
- Убедиться, что компоненты правильно обрабатывают запросы.
- Обнаруживать и предотвращать ошибки на ранних стадиях.
- Сохранять функциональность при изменении кода.

🔹 Тестирование API-запросов

1. Мокирование запросов с MSW
MSW позволяет имитировать серверные ответы без изменения кода компонента.

Пример настройки MSW:

import { setupServer } from 'msw/node';
import { rest } from 'msw';

const server = setupServer(
rest.get('/api/data', (req, res, ctx) => {
return res(ctx.json({ message: 'Success' }));
})
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

Тестирование компонента:

import { render, screen, waitFor } from '@testing-library/react';
import App from './App';

test('показывает данные после успешного запроса', async () => {
render(<App />);

expect(screen.getByText(/загрузка/i)).toBeInTheDocument();

await waitFor(() => {
expect(screen.getByText(/success/i)).toBeInTheDocument();
});
});


2. Использование jest.fn() для мокирования функций
Если компонент вызывает функцию, переданную через пропсы, можно замокировать её с помощью jest.fn().
const mockFetchData = jest.fn(() => Promise.resolve({ message: 'Success' }));

test('вызывает fetchData при рендере', async () => {
render(<App fetchData={mockFetchData} />);
expect(mockFetchData).toHaveBeenCalledTimes(1);
});


🔹 Тестирование эффектов


useEffect
часто используется для выполнения API-запросов, и важно убедиться, что компонент правильно реагирует на изменения.

1. Проверка побочных эффектов
import { render, screen } from '@testing-library/react';
import App from './App';

test('выполняет побочный эффект при монтировании', () => {
render(<App />);

expect(screen.getByText(/загрузка/i)).toBeInTheDocument();
});

2. Тестирование отмены эффектов
Если эффект включает очистку (например, отмену запросов), это тоже можно протестировать.
test('отменяет запрос при размонтировании', () => {
const mockFetchData = jest.fn(() => Promise.resolve());
const { unmount } = render(<App fetchData={mockFetchData} />);

unmount();
expect(mockFetchData).toHaveBeenCalledTimes(1);
});


🔹 Рекомендации


1. Мокируйте API-запросы вместо использования реального сервера. Это делает тесты быстрыми и надёжными.
2. Проверяйте поведение компонентов, а не их внутреннюю реализацию.
3. Тестируйте как успешные, так и ошибочные запросы.
4. Используйте cleanup для удаления ненужных эффектов.

🎯 Заключение

Тестирование API и эффектов — это основа стабильного приложения. MSW, Jest и React Testing Library — ваши главные помощники для проверки всех сценариев, от загрузки данных до обработки ошибок. Пишите тесты, и ваш код скажет вам спасибо! 😊

ReactJs Daily | #testing
🚀 Drag-and-Drop в React: простое руководство

Функционал drag-and-drop часто используется для организации элементов, перемещения файлов и других интерактивных действий. Сегодня разберём, как его реализовать в React с минимальными усилиями!

🔹 Основные шаги для реализации

1. Добавление событий перетаскивания
В HTML5 есть встроенные события для drag-and-drop:
- onDragStart — инициирует перетаскивание.
- onDragOver — позволяет элементу быть зоной для сброса.
- onDrop — срабатывает при отпускании элемента.

2. Создание базового компонента
Вот пример, где мы добавляем элемент для перетаскивания и область для сброса.

import React, { useState } from 'react';

const DragAndDrop = () => {
const [droppedItem, setDroppedItem] = useState('');

const handleDragStart = (e, data) => {
e.dataTransfer.setData('text/plain', data);
};

const handleDrop = (e) => {
e.preventDefault();
const data = e.dataTransfer.getData('text/plain');
setDroppedItem(data);
};

const handleDragOver = (e) => {
e.preventDefault();
};

return (
<div>
<div
draggable
onDragStart={(e) => handleDragStart(e, 'Перетащено!')}
style={{ width: '150px', padding: '10px', backgroundColor: '#f0f0f0', cursor: 'grab', marginBottom: '20px' }}
>
Перетащи меня!
</div>

<div
onDrop={handleDrop}
onDragOver={handleDragOver}
style={{ width: '200px', height: '100px', backgroundColor: '#e0e0e0' }}
>
Брось сюда!
</div>

{droppedItem && <p>Результат: {droppedItem}</p>}
</div>
);
};

export default DragAndDrop;


🔹 Объяснение

1. `draggable`
Устанавливает элемент как "перетаскиваемый".
2. `dataTransfer`
Используется для передачи данных между событиями onDragStart и onDrop.
3. `onDragOver`
Предотвращает поведение по умолчанию, чтобы позволить сброс элемента.
4. Стилизация
Добавляем визуальные подсказки, чтобы пользователю было понятно, где можно сбрасывать объект.

🔹 Использование библиотеки `react-dnd`

Для более сложных сценариев, таких как перетаскивание списков или взаимодействие с несколькими элементами, можно использовать библиотеку react-dnd.

Установка:
npm install react-dnd react-dnd-html5-backend


Пример использования:

import React from 'react';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

const ItemType = 'BOX';

const DraggableItem = ({ id }) => {
const [, dragRef] = useDrag(() => ({
type: ItemType,
item: { id },
}));

return (
<div ref={dragRef} style={{ padding: '10px', backgroundColor: '#f0f0f0', marginBottom: '10px', cursor: 'grab' }}>
Элемент {id}
</div>
);
};

const DropZone = ({ onDrop }) => {
const [, dropRef] = useDrop(() => ({
accept: ItemType,
drop: (item) => onDrop(item.id),
}));

return (
<div
ref={dropRef}
style={{ width: '200px', height: '100px', backgroundColor: '#e0e0e0' }}
>
Брось сюда!
</div>
);
};

const DragAndDropExample = () => {
const handleDrop = (id) => {
alert(`Вы перетащили элемент ${id}`);
};

return (
<DndProvider backend={HTML5Backend}>
<DraggableItem id={1} />
<DraggableItem id={2} />
<DropZone onDrop={handleDrop} />
</DndProvider>
);
};

export default DragAndDropExample;


🔹 Преимущества использования `react-dnd`

- Удобная работа с множеством элементов.
- Поддержка сложных сценариев (например, перетаскивание между списками).
- Расширенные возможности кастомизации поведения.

🎯 Заключение

React упрощает реализацию drag-and-drop благодаря событиям HTML5, а для сложных задач можно использовать мощные библиотеки вроде react-dnd

ReactJs Daily | #begginers
👍1
🚀 Создание интерактивных графиков и диаграмм в React

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

🔹 Почему это важно?

Интерактивные графики:
- делают данные визуально привлекательными,
- помогают пользователям находить скрытые закономерности,
- поддерживают взаимодействие (наведение, клики, масштабирование).

🔹 Популярные библиотеки для визуализации в React

1. Recharts
Простая в использовании библиотека с широким выбором графиков. Подходит для большинства стандартных задач.

Пример использования:
import { LineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid } from 'recharts';

const data = [
{ name: 'Янв', uv: 400 },
{ name: 'Фев', uv: 300 },
{ name: 'Март', uv: 500 },
];

const MyChart = () => (
<LineChart width={400} height={300} data={data}>
<CartesianGrid stroke="#f5f5f5" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Line type="monotone" dataKey="uv" stroke="#ff7300" />
</LineChart>
);

export default MyChart;


2. Chart.js
Очень гибкая библиотека для создания сложных графиков. Подходит для интерактивных приложений.

Пример использования:
import { Line } from 'react-chartjs-2';

const data = {
labels: ['Янв', 'Фев', 'Март'],
datasets: [
{
label: 'Продажи',
data: [400, 300, 500],
borderColor: 'rgba(75, 192, 192, 1)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
},
],
};

const MyChart = () => <Line data={data} />;

export default MyChart;



3. D3.js
Мощнейшая библиотека для сложных и кастомных визуализаций. Требует больше знаний, но позволяет реализовать практически любые идеи.

Пример использования:
import React, { useEffect, useRef } from 'react';
import * as d3 from 'd3';

const BarChart = () => {
const chartRef = useRef();

useEffect(() => {
const data = [10, 20, 30, 40, 50];
const svg = d3
.select(chartRef.current)
.attr('width', 400)
.attr('height', 200);

svg
.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', (_, i) => i * 50)
.attr('y', (d) => 200 - d * 4)
.attr('width', 40)
.attr('height', (d) => d * 4)
.attr('fill', 'teal');
}, []);

return <svg ref={chartRef}></svg>;
};

export default BarChart;


🔹 Фишки интерактивных графиков

- События взаимодействия: Вывод данных при наведении, фильтрация или детализация.
- Динамическое обновление: Применение real-time данных.
- Масштабирование и прокрутка: Особенно полезно для больших наборов данных.
- Анимации: Улучшают пользовательский опыт (например, при загрузке данных).

🔹 Что выбрать?

- Recharts: для быстрых и простых решений.
- Chart.js: для сложных, но стандартных графиков.
- D3.js: для кастомных визуализаций и нестандартных задач.

🎯 Заключение

Интерактивные графики помогут сделать ваше приложение не только красивым, но и полезным😊

ReactJs Daily | #pro
👍2🔥1
🚀 Динамические поля с React Hook Form и Controller

Если в вашем приложении нужно создавать формы с динамическими полями, то React Hook Form в сочетании с useFieldArray и Controller станет идеальным решением. Этот подход особенно полезен, когда вы работаете с управляемыми компонентами или сторонними библиотеками UI

🔹Что мы будем делать?

- Создадим форму с динамическими полями.
- Используем useFieldArray для управления массивом данных.
- Подключим контролируемые компоненты через Controller.

🔹Реализация

import React from 'react';
import { useForm, useFieldArray, Controller } from 'react-hook-form';

function DynamicForm() {
const { control, handleSubmit } = useForm({
defaultValues: {
users: [{ name: '', age: '' }],
},
});

const { fields, append, remove } = useFieldArray({
control,
name: 'users',
});

const onSubmit = (data) => {
console.log(data);
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
{fields.map((field, index) => (
<div key={field.id} style={{ marginBottom: '10px' }}>
<Controller
name={`users.${index}.name`}
control={control}
render={({ field }) => (
<input {...field} placeholder="Имя" />
)}
/>
<Controller
name={`users.${index}.age`}
control={control}
render={({ field }) => (
<input {...field} placeholder="Возраст" type="number" />
)}
/>
<button type="button" onClick={() => remove(index)}>
Удалить
</button>
</div>
))}
<button type="button" onClick={() => append({ name: '', age: '' })}>
Добавить поле
</button>
<button type="submit">Отправить</button>
</form>
);
}

export default DynamicForm;


🔹 Как это работает?

1. useFieldArray
- Позволяет управлять массивами данных, например, добавлять или удалять элементы.
- fields — текущие элементы массива.
- append — добавляет новый объект в массив.
- remove — удаляет элемент по индексу.

2. Controller
- Используется для интеграции управляемых компонентов.
- Автоматически связывает value, onChange и другие свойства с вашим компонентом.

3. Динамические поля
- С каждым вызовом append добавляется новый объект с полями, соответствующими вашему массиву.
- При удалении элемент удаляется из массива и формы.

🔹 Преимущества подхода

- Простота работы с массивами данных.
- Гибкость: подходит для любых сторонних компонентов.
- Производительность: React Hook Form оптимизирован для минимизации ререндеров.

🎯 Заключение

React Hook Form это удобный и мощный инструмент для работы с полями. Это упрощает работу с управляемыми компонентами и добавляет гибкость вашему коду. Попробуйте интегрировать эту функциональность в своих проектах!

ReactJs Daily | #begginers
👍1