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

Где применяется Hook в State Manager?

2.7 Senior🔥 211 комментариев
#React#State Management

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

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

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

Применение Hooks в State Manager

Hooks используются для интеграции с глобальным состоянием (state management) в React. Это позволяет получать данные из store и изменять их прямо из компонентов.

React Hooks для State Management

1. useState - локальное состояние компонента

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

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

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

2. useReducer - управление сложным состоянием

Удобен для состояния с несколькими значениями и правилами изменения:

const initialState = { count: 0, error: null };

const reducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1, error: null };
    case 'DECREMENT':
      return { ...state, count: state.count - 1, error: null };
    case 'ERROR':
      return { ...state, error: action.payload };
    default:
      return state;
  }
};

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
      {state.error && <p className="error">{state.error}</p>}
    </div>
  );
}

Context + Hooks (встроенный State Manager)

Для глобального состояния можно использовать React Context с Hooks:

// Создаём контекст
const AuthContext = createContext();

// Создаём провайдер с состоянием
function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);

  const login = async (email, password) => {
    setLoading(true);
    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify({ email, password })
      });
      const data = await response.json();
      setUser(data);
    } finally {
      setLoading(false);
    }
  };

  const logout = () => {
    setUser(null);
  };

  const value = { user, loading, login, logout };

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

// Кастомный хук для использования контекста
function useAuth() {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within AuthProvider');
  }
  return context;
}

// Использование в компонентах
function Profile() {
  const { user, login, logout } = useAuth();

  if (!user) {
    return <button onClick={() => login('test@example.com', 'password')}>Login</button>;
  }

  return (
    <div>
      <p>Welcome, {user.name}</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

Redux с Hooks

Redux предоставляет хуки для работы со store:

import { useSelector, useDispatch } from 'react-redux';

// Действие
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case INCREMENT:
      return state + 1;
    case DECREMENT:
      return state - 1;
    default:
      return state;
  }
};

// Компонент с Hooks
function Counter() {
  // useSelector - получить состояние из store
  const count = useSelector(state => state.counter);
  
  // useDispatch - отправить действие
  const dispatch = useDispatch();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => dispatch({ type: INCREMENT })}>+</button>
      <button onClick={() => dispatch({ type: DECREMENT })}>-</button>
    </div>
  );
}

Redux Thunk для асинхронных операций:

// Асинхронное действие (thunk)
const fetchUser = (userId) => async (dispatch) => {
  dispatch({ type: 'FETCH_USER_START' });
  try {
    const response = await fetch(`/api/users/${userId}`);
    const data = await response.json();
    dispatch({ type: 'FETCH_USER_SUCCESS', payload: data });
  } catch (error) {
    dispatch({ type: 'FETCH_USER_ERROR', payload: error.message });
  }
};

// Компонент
function UserProfile({ userId }) {
  const user = useSelector(state => state.user.data);
  const loading = useSelector(state => state.user.loading);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(fetchUser(userId));
  }, [userId, dispatch]);

  if (loading) return <p>Loading...</p>;
  if (!user) return <p>No user found</p>;

  return <p>Name: {user.name}</p>;
}

Zustand - современный State Manager

Популярная альтернатива Redux с Hooks:

import create from 'zustand';

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

// Использование
function Counter() {
  const count = useCounterStore(state => state.count);
  const increment = useCounterStore(state => state.increment);

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

Zustand с асинхронностью:

const useUserStore = create((set) => ({
  user: null,
  loading: false,
  fetchUser: async (userId) => {
    set({ loading: true });
    try {
      const response = await fetch(`/api/users/${userId}`);
      const data = await response.json();
      set({ user: data, loading: false });
    } catch (error) {
      set({ loading: false });
      throw error;
    }
  }
}));

function Profile({ userId }) {
  const { user, loading, fetchUser } = useUserStore();

  useEffect(() => {
    fetchUser(userId);
  }, [userId, fetchUser]);

  if (loading) return <p>Loading...</p>;
  return <p>{user?.name}</p>;
}

Jotai - атомное состояние

Минималистичный State Manager на основе атомов:

import { atom, useAtom } from 'jotai';

const countAtom = atom(0);

function Counter() {
  const [count, setCount] = useAtom(countAtom);

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

Сравнение подходов

СпособСложностьBoilerplateПроизводительностьКогда использовать
useStateНизкаяНетОтличнаяЛокальное состояние компонента
useReducerСредняяНекоторыйОтличнаяСложное локальное состояние
Context + HooksСредняяНекоторыйХорошаяСреднее приложение
ReduxВысокаяМногоОтличнаяБольшое приложение с сложной логикой
ZustandНизкаяМинимумОтличнаяСовременные приложения среднего размера
JotaiНизкаяМинимумОтличнаяДекларативное управление состоянием

На практике: мой выбор

Для большинства проектов использую такую стратегию:

// 1. Локальное состояние - useState
function SearchInput() {
  const [query, setQuery] = useState('');
  return <input value={query} onChange={e => setQuery(e.target.value)} />;
}

// 2. Состояние между несколькими компонентами - Context + useContext
const ThemeContext = createContext();

// 3. Глобальное состояние приложения - Zustand
const useAppStore = create((set) => ({
  user: null,
  setUser: (user) => set({ user })
}));

// 4. Серверное состояние - React Query (useQuery, useMutation)
import { useQuery } from '@tanstack/react-query';

function Posts() {
  const { data, isLoading } = useQuery({
    queryKey: ['posts'],
    queryFn: () => fetch('/api/posts').then(r => r.json())
  });

  return isLoading ? <p>Loading...</p> : <div>{/* posts */}</div>;
}

Вывод

Hooks в State Manager позволяют:

  • Получать состояние из store в компонент
  • Изменять состояние dispatch-ом
  • Подписываться на изменения
  • Избегать prop drilling (передачи props через множество уровней)

Выбор между встроенным React Context, Redux, Zustand зависит от размера и сложности приложения. Для новых проектов рекомендую Zustand или Context, так как они проще Redux, но мощнее обычного useState.