← Назад к вопросам

Как работают фазы Virtual DOM в React?

2.2 Middle🔥 231 комментариев
#React#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Обзор технологий для работы с компонентами

На протяжении карьеры Frontend Developer я работал с различными подходами и библиотеками для создания и управления компонентами. Расскажу о наиболее значимых и актуальных решениях.

React - основной инструмент

В большинстве проектов я использовал React, как основной фреймворк для работы с компонентами:

// Функциональные компоненты (современный подход)
function UserCard({ name, email, avatar }) {
  return (
    <div className="card">
      <img src={avatar} alt={name} />
      <h3>{name}</h3>
      <p>{email}</p>
    </div>
  );
}

// С хуками
function Counter() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    document.title = `Счётчик: ${count}`;
  }, [count]);
  
  return (
    <div>
      <p>Количество: {count}</p>
      <button onClick={() => setCount(count + 1)}>Увеличить</button>
    </div>
  );
}

State Management решения

Redux / Redux Toolkit

Для сложного состояния приложения:

// Redux Toolkit slice
import { createSlice } from '@reduxjs/toolkit';

const userSlice = createSlice({
  name: 'user',
  initialState: {
    data: null,
    loading: false,
    error: null
  },
  reducers: {
    setUser: (state, action) => {
      state.data = action.payload;
    }
  }
});

export default userSlice.reducer;

// Использование в компоненте
import { useSelector, useDispatch } from 'react-redux';

function Profile() {
  const user = useSelector(state => state.user.data);
  const dispatch = useDispatch();
  
  return <div>{user?.name}</div>;
}

React Context + useReducer

Для среднего уровня сложности:

const AuthContext = createContext();

function AuthProvider({ children }) {
  const [state, dispatch] = useReducer(authReducer, initialState);
  
  return (
    <AuthContext.Provider value={{ state, dispatch }}>
      {children}
    </AuthContext.Provider>
  );
}

function useAuth() {
  return useContext(AuthContext);
}

Zustand

Лёгкое и быстрое решение для состояния:

import create from 'zustand';

const useUserStore = create((set) => ({
  user: null,
  setUser: (user) => set({ user }),
  logout: () => set({ user: null })
}));

// Использование
function App() {
  const { user, setUser } = useUserStore();
  return <div>{user?.name}</div>;
}

UI компоненты и дизайн системы

Material-UI (MUI)

Для быстрого прототипирования:

import { Button, Card, TextField } from '@mui/material';

function LoginForm() {
  return (
    <Card>
      <TextField label="Email" />
      <Button variant="contained">Войти</Button>
    </Card>
  );
}

Tailwind CSS

Для современных проектов с custom дизайном:

function Button({ children, variant = 'primary' }) {
  const baseStyles = 'px-4 py-2 rounded font-medium';
  const variants = {
    primary: 'bg-blue-500 text-white hover:bg-blue-600',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300'
  };
  
  return (
    <button className={`${baseStyles} ${variants[variant]}`}>
      {children}
    </button>
  );
}

Shadcn/ui и Storybook

Для документирования компонентов:

// Storybook файл
import Button from './Button';

export default {
  title: 'Components/Button',
  component: Button
};

export const Primary = () => <Button variant="primary">Нажми</Button>;
export const Secondary = () => <Button variant="secondary">Отмена</Button>;

Работа с формами

React Hook Form

Лёгкая и производительная библиотека:

import { useForm } from 'react-hook-form';

function RegistrationForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email', { required: true })} />
      {errors.email && <span>Email обязателен</span>}
      <button type="submit">Зарегистрироваться</button>
    </form>
  );
}

Formik

Для более сложных форм:

import { Formik, Form, Field } from 'formik';

function MyForm() {
  return (
    <Formik
      initialValues={{ email: '' }}
      onSubmit={(values) => console.log(values)}
    >
      <Form>
        <Field name="email" type="email" />
        <button type="submit">Отправить</button>
      </Form>
    </Formik>
  );
}

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

Jest + React Testing Library

Для unit тестов:

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

test('Button отображает текст', () => {
  render(<Button>Нажми</Button>);
  expect(screen.getByText('Нажми')).toBeInTheDocument();
});

test('Button вызывает onClick при клике', () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>Нажми</Button>);
  screen.getByText('Нажми').click();
  expect(handleClick).toHaveBeenCalled();
});

Cypress / Playwright

Для E2E тестов:

describe('Login Form', () => {
  it('успешно логинит пользователя', () => {
    cy.visit('/login');
    cy.get('input[name=email]').type('user@example.com');
    cy.get('input[name=password]').type('password123');
    cy.get('button[type=submit]').click();
    cy.url().should('include', '/dashboard');
  });
});

Next.js для SSR компонентов

// Server Component
export default async function UserList() {
  const users = await fetchUsers();
  
  return (
    <ul>
      {users.map(user => (
        <UserItem key={user.id} user={user} />
      ))}
    </ul>
  );
}

// Client Component
'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

Web Components и Custom Elements

Для переиспользования между фреймворками:

class UserCard extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `
      <div class="card">
        <h3>${this.getAttribute('name')}</h3>
        <p>${this.getAttribute('email')}</p>
      </div>
    `;
  }
}

customElements.define('user-card', UserCard);

// Использование
<user-card name="Иван" email="ivan@example.com"></user-card>

TypeScript для типизации компонентов

interface UserCardProps {
  id: string;
  name: string;
  email: string;
  avatar?: string;
  onSelect?: (id: string) => void;
}

function UserCard({ 
  id, 
  name, 
  email, 
  avatar,
  onSelect 
}: UserCardProps): JSX.Element {
  return (
    <div onClick={() => onSelect?.(id)}>
      {avatar && <img src={avatar} alt={name} />}
      <h3>{name}</h3>
      <p>{email}</p>
    </div>
  );
}

Микрофронтенды и Module Federation

Для масштабных проектов с несколькими командами:

// webpack.config.js
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        mfe1: 'mfe1@http://localhost:3001/remoteEntry.js',
        mfe2: 'mfe2@http://localhost:3002/remoteEntry.js'
      },
      shared: ['react', 'react-dom']
    })
  ]
};

Резюме использованных технологий

  • React - основной фреймворк
  • Redux / Zustand - управление состоянием
  • Tailwind CSS / Material-UI - стилизация
  • React Hook Form / Formik - работа с формами
  • Jest / React Testing Library / Cypress - тестирование
  • Next.js - SSR и оптимизация
  • TypeScript - типизация
  • Storybook - документирование
  • Web Components - кроссфреймворковое переиспользование

Выбор технологии зависит от:

  • Размера и сложности проекта
  • Требований к производительности
  • Опыта команды
  • Бюджета и сроков

Главное правило: не используй инструмент, если не понимаешь, зачем он нужен.

Как работают фазы Virtual DOM в React? | PrepBro