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

Для чего используется Hook useSellect?

1.2 Junior🔥 61 комментариев
#Другое

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

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

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

Hook useSelector (Redux)

useSelector — это хук из React Redux для чтения данных из Redux store. Это один из самых часто используемых хуков при работе с Redux.

Что такое useSelector

useSelector — это функция, которая позволяет компоненту подписаться на данные из Redux store и автоматически перерендериться при изменении этих данных.

import { useSelector } from 'react-redux';

function UserProfile() {
  // Получаем userId из Redux store
  const userId = useSelector((state) => state.auth.userId);
  
  return <div>User ID: {userId}</div>;
}

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

Без Redux (prop drilling):

// App.js
function App() {
  const [user, setUser] = useState({ id: 123, name: 'John' });
  return <Header user={user} />;
}

// Header.js
function Header({ user }) {
  return <UserInfo user={user} />;
}

// UserInfo.js
function UserInfo({ user }) {
  return <div>{user.name}</div>;
}

// Проблема: user проходит через 3+ уровня компонентов!

С Redux (useSelector):

// UserInfo.js (прямой доступ без props)
function UserInfo() {
  const user = useSelector((state) => state.auth.user);
  return <div>{user.name}</div>;
}

Синтаксис useSelector

const value = useSelector(selector, equalityFn?);

Параметры:

  • selector — функция, которая извлекает данные из state
  • equalityFn — опциональная функция для проверки равенства (по умолчанию ===)

Примеры

Пример 1: Простое извлечение

import { useSelector } from 'react-redux';

function Dashboard() {
  // Redux state:
  // { user: { id: 1, name: 'John', email: 'john@example.com' } }
  
  const userId = useSelector((state) => state.user.id);
  const userName = useSelector((state) => state.user.name);
  
  return (
    <div>
      <h1>{userName}</h1>
      <p>ID: {userId}</p>
    </div>
  );
}

Пример 2: Получение целого объекта

function UserProfile() {
  // Получить весь user объект
  const user = useSelector((state) => state.user);
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

Пример 3: Вычисления в selector

function Cart() {
  // Вычислить сумму в selector
  const total = useSelector((state) => {
    return state.cart.items.reduce(
      (sum, item) => sum + (item.price * item.quantity),
      0
    );
  });
  
  return <div>Total: ${total}</div>;
}

Пример 4: Условное получение

function AuthorizedContent() {
  const isAdmin = useSelector((state) => state.auth.user?.role === 'admin');
  
  if (!isAdmin) return <div>Access denied</div>;
  
  return <AdminPanel />;
}

Оптимизация: Memoization

Проблема: излишние перерендеры

function UserList() {
  // Это создаёт НОВЫЙ массив при каждом вызове selector!
  const users = useSelector((state) => state.users.filter(u => u.active));
  
  // Компонент перерендеривается каждый раз,
  // даже если actual данные не изменились!
  console.log('Rendered'); // выведется много раз
  
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

Решение 1: useCallback

function UserList() {
  const users = useSelector(
    // Мемоизируем selector
    useCallback(
      (state) => state.users.filter(u => u.active),
      []
    )
  );
  
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

Решение 2: Reselect (рекомендуется)

import { createSelector } from 'reselect';

// Мемоизированный selector
const selectActiveUsers = createSelector(
  (state) => state.users,
  (users) => users.filter(u => u.active)
);

function UserList() {
  const users = useSelector(selectActiveUsers);
  
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

Решение 3: Shallow equal

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

function UserInfo() {
  // Используем shallow equality для объектов
  const { name, email } = useSelector(
    (state) => ({
      name: state.user.name,
      email: state.user.email
    }),
    shallowEqual // не перерендер если значения внутри одинаковые
  );
  
  return (
    <div>
      <p>{name}</p>
      <p>{email}</p>
    </div>
  );
}

Redux state структура (best practices)

// Хорошая структура для useSelector
const state = {
  auth: {
    isLoading: false,
    user: null,
    error: null
  },
  users: {
    list: [],
    selectedId: null
  },
  posts: {
    byId: { '1': {...}, '2': {...} },
    allIds: ['1', '2']
  }
};

// Селекторы (отдельный файл)
export const selectIsAuthenticated = (state) => state.auth.user !== null;
export const selectCurrentUser = (state) => state.auth.user;
export const selectAllUsers = (state) => state.users.list;
export const selectUserById = (state, userId) => 
  state.users.list.find(u => u.id === userId);

Практический пример с действиями

// Redux store
const initialState = {
  user: { id: null, name: null, role: null },
  isLoading: false,
  error: null
};

const authReducer = (state = initialState, action) => {
  switch(action.type) {
    case 'LOGIN_START':
      return { ...state, isLoading: true };
    case 'LOGIN_SUCCESS':
      return { ...state, user: action.payload, isLoading: false };
    case 'LOGIN_ERROR':
      return { ...state, error: action.payload, isLoading: false };
    default: return state;
  }
};

// Компонент с useSelector
function LoginForm() {
  const dispatch = useDispatch();
  const isLoading = useSelector((state) => state.isLoading);
  const error = useSelector((state) => state.error);
  const user = useSelector((state) => state.user);
  
  const handleLogin = (credentials) => {
    dispatch({ type: 'LOGIN_START' });
    // API call...
    dispatch({ type: 'LOGIN_SUCCESS', payload: userData });
  };
  
  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (user.id) return <div>Welcome, {user.name}!</div>;
  
  return <form onSubmit={handleLogin}>...</form>;
}

Сравнение с альтернативами

// 1. useSelector (Redux)
const user = useSelector((state) => state.user);

// 2. Context API
const user = useContext(UserContext);

// 3. Props
<Component user={user} />

// Рекомендуется:
// - Redux для больших приложений
// - Context для небольших
// - Props для локального состояния

Частые ошибки

Ошибка 1: Создание нового объекта в selector

// ❌ ПЛОХО: новый объект при каждом вызове
const user = useSelector((state) => ({
  name: state.user.name,
  email: state.user.email
}));
// Компонент перерендеривается всегда!

// ✅ ХОРОШО: используй shallowEqual
const user = useSelector(
  (state) => ({
    name: state.user.name,
    email: state.user.email
  }),
  shallowEqual
);

Ошибка 2: Сложные вычисления в selector

// ❌ ПЛОХО: тяжелые вычисления
const expensiveValue = useSelector((state) => {
  return state.items.reduce((acc, item) => {
    // сложные вычисления...
  }, {});
});

// ✅ ХОРОШО: используй createSelector
const selectExpensiveValue = createSelector(
  (state) => state.items,
  (items) => items.reduce(...)
);
const expensiveValue = useSelector(selectExpensiveValue);

Ошибка 3: useSelector в циклах

// ❌ ПЛОХО: нарушает правила хуков
function UsersList() {
  for (let i = 0; i < 10; i++) {
    const user = useSelector((state) => state.users[i]); // error!
  }
}

// ✅ ХОРОШО: вызови useSelector один раз
function UsersList() {
  const users = useSelector((state) => state.users);
  return users.map((user) => <User key={user.id} user={user} />);
}

Итого: useSelector

Что это: Хук для чтения данных из Redux store

Назначение:

  • Избежать prop drilling
  • Автоматическое перерендеривание при изменении данных
  • Селектора для извлечения конкретных данных

Использование:

const data = useSelector((state) => state.path.to.data);

Оптимизация:

  • createSelector (Reselect)
  • shallowEqual
  • Мемоизированные селекторы

Правила:

  • Один selector per использование
  • Мемоизируй сложные вычисления
  • Используй объекты state для структурирования

useSelector — это основной способ подключения компонентов к Redux store.