Пишется ли проект полностью на Context в React
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Пишется ли проект полностью на Context в React?
Короткий ответ: НЕТ, это плохая идея. React Context - это инструмент для передачи значений глубоко вложенным компонентам, а не для управления всем состоянием приложения. Это частая ошибка junior-разработчиков.
Чем занимается Context
Context предназначен для:
// 1. Передача глобальных данных
const ThemeContext = React.createContext<"light" | "dark">("light");
// 2. Авторизация и user данные
const AuthContext = React.createContext<User | null>(null);
// 3. Конфигурация приложения
const AppConfigContext = React.createContext<Config>({});
// Использование - просто читаем значение
function Header() {
const { currentUser } = useContext(AuthContext);
return <div>{currentUser?.name}</div>;
}
Context хорош для данных которые:
- Редко меняются (тема, язык, права доступа)
- Нужны всему приложению
- Не требуют сложной логики обновления
Когда Context становится проблемой
1. Частые обновления состояния
// ПЛОХО - Context обновляется много раз
const [filters, setFilters] = useState(initialFilters);
const [sortBy, setSortBy] = useState("date");
const [pagination, setPagination] = useState({ page: 1, limit: 10 });
const value = { filters, setFilters, sortBy, setSortBy, pagination, setPagination };
// Каждое изменение вызывает ре-рендер ВСЕХ потребителей Context
// Это медленно!
export const FilterContext = React.createContext(value);
2. Проблемы с производительностью
// Это НЕ оптимально
function FilterProvider({ children }: { children: React.ReactNode }) {
const [filters, setFilters] = useState({});
const [items, setItems] = useState([]); // много состояния
const [loading, setLoading] = useState(false);
// Каждое изменение любого из этих = ре-рендер всех children
const value = { filters, setFilters, items, setItems, loading, setLoading };
return (
<FilterContext.Provider value={value}>
{children}
</FilterContext.Provider>
);
}
Проблема: если изменилось loading, перерендерятся ВСЕ компоненты которые используют FilterContext, даже если они не используют loading.
3. Сложная логика обновления
// Context не подходит для таких вещей
function useFilters() {
const [filters, setFilters] = useState({});
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const applyFilters = useCallback(async (newFilters) => {
setLoading(true);
try {
const response = await api.getItems(newFilters);
// сложная логика
// нормализация
// кэширование
setFilters(newFilters);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, []);
// Это должно быть в отдельном хуке или state management
}
Правильная архитектура
// 1. Context для глобальных данных
const ThemeContext = React.createContext<Theme>("light");
const AuthContext = React.createContext<User | null>(null);
// 2. Custom hooks для бизнес-логики
function useFilters() {
const [state, dispatch] = useReducer(filtersReducer, initialState);
const applyFilters = useCallback((newFilters) => {
dispatch({ type: "APPLY_FILTERS", payload: newFilters });
}, []);
return { state, applyFilters };
}
// 3. State management для сложного состояния
// Используйте: Redux, Zustand, Jotai, Recoil
// (если Context не справляется)
// 4. Local state для компонента
function MyComponent() {
const [localState, setLocalState] = useState();
// ...
}
Пример неправильного использования Context
// ПЛОХО - всё состояние в Context
const AppContext = React.createContext<AppState>(initialState);
function AppProvider({ children }: { children: React.ReactNode }) {
const [users, setUsers] = useState([]);
const [posts, setPosts] = useState([]);
const [comments, setComments] = useState([]);
const [notifications, setNotifications] = useState([]);
const [filters, setFilters] = useState({});
const [sortBy, setSortBy] = useState("date");
const [currentUser, setCurrentUser] = useState(null);
const [theme, setTheme] = useState("light");
// ... ещё 20 переменных
// Когда что-то меняется - ВСЁ перерендерится
const value = { /* огромный объект */ };
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
}
Правильное использование Context
// ХОРОШО - разделили по смыслу
// 1. Авторизация - редко меняется
const AuthContext = React.createContext<AuthState>(initialAuth);
function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// загружаем user один раз при mount
fetchCurrentUser();
}, []);
return (
<AuthContext.Provider value={{ user, loading }}>
{children}
</AuthContext.Provider>
);
}
// 2. Тема - редко меняется
const ThemeContext = React.createContext<"light" | "dark">("light");
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<"light" | "dark">("light");
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
);
}
// 3. Данные списка - часто меняются
// используем useReducer или state management
function usePostsList() {
const [state, dispatch] = useReducer(reducer, initialState);
const fetchPosts = useCallback((filters) => {
dispatch({ type: "LOADING" });
api.getPosts(filters).then(data => {
dispatch({ type: "SUCCESS", payload: data });
});
}, []);
return { ...state, fetchPosts };
}
Когда нужен настоящий State Management
Используйте Redux, Zustand или подобные когда:
// 1. Много состояния которое часто меняется
const store = createStore({
filters: {},
sortBy: "date",
items: [],
selectedIds: [],
// ...
});
// 2. Сложная логика обновления
store.on("APPLY_FILTERS", (newFilters) => {
// валидация
// кэширование
// отправка на сервер
});
// 3. Нужна история изменений (undo/redo)
store.undo();
store.redo();
// 4. Нужна отладка и time-travel
devTools.inspect();
Лучшая практика структуры
// Project structure
src/
contexts/
AuthContext.tsx // только авторизация
ThemeContext.tsx // только тема
hooks/
useFilters.ts // бизнес-логика фильтров
usePostsList.ts // логика списка
useAuth.ts // обёртка над AuthContext
store/ // если нужен Redux/Zustand
store.ts
slices/
components/
// используют hooks и Context по необходимости
Итоговый совет
Context - это НЕ state management, это инструмент для пробрасывания значений вниз по дереву. Если вы используете Context для всего состояния, у вас будут проблемы с производительностью и поддерживаемостью.
За Context оставьте:
- Авторизация
- Тема
- Язык
- Права доступа
- Глобальные конфиги
Для всего остального используйте hooks и local state, или настоящий state management если состояние сложное.