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

Добро пожаловать в ReactJs Dail - канал для разработчиков, увлеченных React! Здесь вы найдете все самое важное и актуальное в экосистеме React
Download Telegram
ReactJs Daily
🚀 Часть 1: Введение в Recoil и работа с атомами Recoil — это легковесная библиотека для управления глобальным состоянием в React. Разработанная Facebook, она направлена на решение задач, с которыми разработчики сталкиваются при работе с React Context API…
🚀 Часть 2: Селекторы в Recoil — вычисляемое состояние и работа с зависимостями

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

🔹 Что такое селекторы?
Селекторы в Recoil — это функции, которые вычисляют состояние на основе атомов или других селекторов. Они позволяют извлекать, фильтровать или комбинировать данные, не изменяя сами атомы.

Представьте, что у вас есть список задач, и вы хотите получить только завершенные. Селектор сделает это за вас!

🔹 Как создать селектор
Селекторы создаются с помощью selector из Recoil. Вы передаете объект с ключом и функцией get, которая описывает, как извлечь или вычислить данные.

Пример:

import { atom, selector } from "recoil";

// Атом: список задач
const tasksState = atom({
key: "tasksState",
default: [
{ id: 1, text: "Учить Recoil", completed: true },
{ id: 2, text: "Сделать проект", completed: false },
],
});

// Селектор: завершенные задачи
const completedTasksSelector = selector({
key: "completedTasksSelector",
get: ({ get }) => {
const tasks = get(tasksState);
return tasks.filter((task) => task.completed);
},
});


🔹 Использование селекторов
Вы можете использовать селектор в компонентах так же, как атомы, через useRecoilValue.

import { useRecoilValue } from "recoil";

function CompletedTasks() {
const completedTasks = useRecoilValue(completedTasksSelector);

return (
<ul>
{completedTasks.map((task) => (
<li key={task.id}>{task.text}</li>
))}
</ul>
);
}


Результат: в списке будут только завершенные задачи.

🔹 Работа с зависимостями
Селекторы автоматически отслеживают изменения в атомах и других селекторах, от которых они зависят. Если исходные данные изменятся, селектор пересчитает свое состояние.

Например, вы можете комбинировать несколько атомов:

const userState = atom({
key: "userState",
default: { name: "Алексей", age: 30 },
});

const userInfoSelector = selector({
key: "userInfoSelector",
get: ({ get }) => {
const user = get(userState);
return `${user.name}, ${user.age} лет`;
},
});


Теперь любое изменение в userState автоматически обновит значение userInfoSelector.

🔹 Асинхронные селекторы
Селекторы поддерживают асинхронные операции, такие как запросы к API. Просто возвращайте Promise из функции get.

const userDataSelector = selector({
key: "userDataSelector",
get: async () => {
const response = await fetch("https://api.example.com/user");
const data = await response.json();
return data;
},
});


🎯 Заключение

Селекторы в Recoil делают управление состоянием более гибким и декларативным. Они помогают не просто хранить данные, но и извлекать нужное состояние из множества атомов, автоматизируя вычисления.


Будет 3-я часть😌

ReactJs Daily | #pro
👍1
🚀 Server Components в React 19: Новый подход к рендерингу

Привет, разработчики! Сегодня поговорим про React Server Components (RSC) — одну из ключевых новых возможностей React 19, которая помогает оптимизировать производительность и упрощает работу с данными.

`
🔹 Что такое Server Components?
Server Components — это способ рендерить React-компоненты на сервере, а не на клиенте. Вместо передачи полного HTML или JSON сервер возвращает "React-структуры" (внутреннее представление компонентов), которые затем рендерятся на клиенте.

Идея в том, чтобы перенести сложную логику (например, загрузку данных) на сервер, оставив клиенту только обновление UI. Это позволяет:
- Уменьшить размер бандла на клиенте.
- Повысить производительность за счет рендеринга тяжелых компонентов на сервере.
- Снизить количество запросов к API с клиента.


🔹 Как это работает?
В React-компоненте, который вы хотите рендерить на сервере, достаточно указать async перед функцией.
Пример:
// Серверный компонент
export default async function ServerComponent() {
const data = await fetchData(); // Логика загрузки данных на сервере
return <div>Данные: {data}</div>;
}

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

🔹 Преимущества Server Components
1. Меньший объем JS на клиенте.
Только UI-компоненты остаются на клиенте, а тяжелая логика работает на сервере.

2. Мгновенная доступность данных.
Загрузка данных происходит на сервере, и клиент получает уже готовый результат без лишних запросов.

3. Повышение безопасности.
Логика работы с секретными данными остается на сервере, исключая их утечку на клиент.


🔹 Использование Server Components вместе с Client Components
React позволяет сочетать Server и Client Components для максимальной гибкости. Например:
// App.jsx
import ClientComponent from './ClientComponent';
import ServerComponent from './ServerComponent';

export default function App() {
return (
<div>
<ServerComponent />
<ClientComponent />
</div>
);
}

Server Components
будут рендериться на сервере, а Client Components останутся на клиенте.


🔹 Ограничения Server Components
- Нельзя использовать хуки React, которые зависят от браузерного окружения (например, useState или useEffect).
- Не предназначены для взаимодействия с DOM напрямую.


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

Попробуйте использовать Server Components в своем следующем проекте и оцените их преимущества!

ReactJs Daily | #begginers
3
📝 Оптимизация обработчиков событий в React: минимизация ререндера и делегирование событий

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

Советы

1. Избегайте анонимных функций в JSX:
Анонимные функции создаются заново при каждом рендере, что может вызывать ненужные рендеры дочерних компонентов.

Плохо:
<button onClick={() => console.log("Клик!")}>Клик</button>


Хоршо:
const handleClick = () => console.log("Клик!");

<button onClick={handleClick}>Клик</button>



2. Используйте `useCallback` для мемоизации функций:
Когда обработчик передается как пропс в дочерний компонент, мемоизируйте его с помощью хука useCallback, чтобы сохранить одну и ту же ссылку между рендерами.

const handleClick = useCallback(() => {
console.log("Клик!");
}, []);



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

Пример:
const handleClick = (event) => {
if (event.target.tagName === "BUTTON") {
console.log(`Кнопка с текстом "${event.target.textContent}" нажата`);
}
};

return (
<div onClick={handleClick}>
<button>Кнопка 1</button>
<button>Кнопка 2</button>
</div>
);


В этом примере обработчик добавлен только на родительский элемент, а не на каждую кнопку.

Результат:
Делегирование событий и правильное использование useCallback помогут вам оптимизировать работу приложения, уменьшить количество обработчиков и предотвратить лишние рендеры.

ReactJs Daily | #shortinfo
👍1🤝1
ReactJs Daily
🚀 Часть 2: Селекторы в Recoil — вычисляемое состояние и работа с зависимостями Привет, друзья! 👋 В первой части мы обсудили атомы в Recoil — основу для управления состоянием. Сегодня поговорим о селекторах — мощном инструменте для вычисления производных…
🚀 Часть 3: Продвинутые техники в Recoil — асинхронное состояние, сложные приложения и отладка

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

🔹 Асинхронное состояние в Recoil
Асинхронное состояние создается с помощью селекторов — вычисляемых значений, которые могут быть как синхронными, так и асинхронными. Для асинхронных задач селектор может возвращать промис, который Recoil обработает автоматически.

Предположим, у нас есть API, которое возвращает список пользователей. Создадим атом и асинхронный селектор для управления состоянием:
import { atom, selector, useRecoilValue } from 'recoil';

// Атом для хранения списка пользователей
const userListAtom = atom({
key: 'userListAtom',
default: [], // По умолчанию пустой массив
});

// Селектор для загрузки данных
const userListSelector = selector({
key: 'userListSelector',
get: async () => {
try {
const response = await fetch('https://api.example.com/users');
if (!response.ok) throw new Error('Ошибка загрузки данных');
return await response.json(); // Возвращаем список пользователей
} catch (error) {
throw error; // Выбрасываем ошибку, чтобы Recoil мог обработать её
}
},
});


В компоненте можно использовать селектор для получения данных:
function UserList() {
const users = useRecoilValue(userListSelector); // Данные автоматически кешируются
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}


🔹 Обработка состояния загрузки и ошибок
Recoil предоставляет метод getLoadable для работы с состоянием селектора. Это удобно для отображения состояния загрузки, ошибок или данных.

import { useRecoilValueLoadable } from 'recoil';

function UserList() {
const userListLoadable = useRecoilValueLoadable(userListSelector);

if (userListLoadable.state === 'loading') {
return <div>Загрузка...</div>;
}

if (userListLoadable.state === 'hasError') {
return <div>Ошибка: {userListLoadable.contents.message}</div>;
}

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


🔹 Recoil в сложных приложениях
Recoil отлично справляется с масштабированием за счет атомов и модульного подхода. В больших приложениях:
1. Разделяйте атомы и селекторы по функциональным модулям.
2. Используйте фичи, такие как DefaultValue, чтобы управлять сбросом состояния.

Пример сброса состояния через атомы:
import { atom, useResetRecoilState } from "recoil";

const formState = atom({
key: "formState",
default: { name: "", email: "" },
});

const Form = () => {
const resetForm = useResetRecoilState(formState);

return (
<button onClick={resetForm}>Сбросить форму</button>
);
};


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


🔹 Отладка Recoil
Recoil предоставляет инструменты для облегчения отладки:
1. Recoil DevTools: Плагин для браузера, который позволяет отслеживать изменения состояния атомов и селекторов.
2. Snapshots: Используйте useRecoilSnapshot для логирования состояния приложения в любой момент.

Пример использования:
import { useRecoilSnapshot } from "recoil";

const Debugger = () => {
const snapshot = useRecoilSnapshot();

console.log("Текущее состояние:", Array.from(snapshot.getNodes_UNSTABLE({ isModified: true })));

return null;
};


Добавьте этот компонент в приложение для мониторинга изменений.


🎯 Заключение

Recoil предлагает мощные инструменты для работы с асинхронным состоянием и построения сложных приложений. А с помощью DevTools и снапшотов вы всегда будете знать, что происходит внутри вашего приложения.

ReactJs Daily | #pro
👍2
🚀 Почему `key` в React так важен и как правильно его использовать?

Привет, друзья! 👋
Если вы работаете с React, то наверняка сталкивались с предупреждением *"Warning: Each child in a list should have a unique 'key' prop"*. Сегодня разберёмся, зачем нужен атрибут key и как он помогает React быть таким быстрым и эффективным.


🔹 Что такое `key`?
Атрибут key — это способ, с помощью которого React отслеживает элементы в списках. Когда список меняется (например, добавляется или удаляется элемент), key помогает React правильно сопоставить старые и новые элементы, избегая лишнего рендера.


🔹 Почему это важно?
Без key React теряет контекст о том, какой элемент списка к чему относится. Это может вызвать:
- Сброс состояния. Например, вы заполнили форму, а React "решил", что это уже другой элемент, и стёр данные.
- Неверное обновление интерфейса. React может случайно поменять местами элементы.

Пример:

const items = ['React', 'Redux', 'Recoil'];

function ItemList() {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li> // Использование index как key
))}
</ul>
);
}


Если добавить элемент в начало списка, React подумает, что всё сдвинулось, и неправильно обновит DOM.


🔹Как правильно использовать `key`?
1. Используйте уникальные идентификаторы. Например, id из ваших данных.

const items = [
{ id: 1, name: 'React' },
{ id: 2, name: 'Redux' },
];

function ItemList() {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}


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


🔹 Почему `key` — это больше, чем просто предупреждение?
Правильное использование key делает ваши приложения:
- Быстрее. React понимает, какие элементы изменились, и минимизирует изменения в DOM.
- Стабильнее. Состояние компонентов не будет теряться.


🎯 Заключение
key — это маленький атрибут, который делает огромную работу. Используйте уникальные и стабильные значения, и ваш код станет не только правильным, но и максимально эффективным!

ReactJs Daily | #begginers
📝 Совет: Используйте 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