Irbisa · Шпаргалка
Паттерны и архитектура
Паттерны композиции, compound components, render props и HOC, error boundaries, порталы, структура папок, дизайн-системы, монорепозитории
Полезно ли ещё разделение на контейнерные и презентационные компоненты, когда есть хуки?
Как принципы SOLID применяются к React-компонентам и хукам?
import type { ReactNode } from 'react'; // I: ask for the fields you use, not the whole `user`function Avatar({ name, src }: { name: string; src: string }) { return <img src={src} alt={name} className="avatar" />;}…Как сделать внедрение зависимостей (DI) в React, например чтобы подменить API-клиент в тестах или Storybook?
import { createContext, use, type ReactNode } from 'react'; interface Api { getUser(id: string): Promise<User>; saveUser(user: User): Promise<void>;}…Как избавиться от prop drilling, не перенося всё в глобальное состояние?
import type { ReactNode } from 'react'; // before: Page -> Layout -> Sidebar -> UserMenu all forward `user`// after: Layout only places what it is givenfunction Layout({ sidebar, children }: { sidebar: ReactNode; children: ReactNode }) { return (…Что такое compound components и как построить такой компонент на контексте?
import { createContext, use, useState, type ReactNode } from 'react'; const TabsContext = createContext<{ active: string; setActive: (id: string) => void } | null>(null); function useTabs() { const ctx = use(TabsContext);…Что такое render prop и когда его всё ещё стоит выбрать вместо кастомного хука?
import { useState, type ReactNode } from 'react'; interface SelectProps<T> { items: T[]; getKey: (item: T) => string; renderOption: (item: T, state: { selected: boolean }) => ReactNode;…Что такое higher-order component (HOC), какие у него проблемы и что его заменило?
import type { ComponentType } from 'react';import { Navigate } from 'react-router'; function withAuth<P extends object>(Wrapped: ComponentType<P>) { function WithAuth(props: P) { const { user, isLoading } = useAuth();…Что такое headless-компонент или headless UI-библиотека (Radix, React Aria, TanStack Table) и зачем строить на ней интерфейс?
import { useId, useState } from 'react'; // Behaviour and ARIA only: no markup, no stylesfunction useDisclosure(initialOpen = false) { const [open, setOpen] = useState(initialOpen); const panelId = useId();…Что такое error boundary и какие ошибки он не ловит?
import { Component, type ErrorInfo, type ReactNode } from 'react'; interface Props { fallback: ReactNode; children: ReactNode }interface State { hasError: boolean } class ErrorBoundary extends Component<Props, State> {…Найдите баг: когда
api.save()падает, fallback error boundary так и не появляется, а в консоли видно необработанный reject промиса.function SaveButton() { async function handleClick() { await api.save(); // rejects when the server is down } return <button onClick={handleClick}>Save</button>;} function Editor() { return ( <ErrorBoundary fallback={<p>Something went wrong</p>}> <SaveButton /> </ErrorBoundary> );}Что такое портал и когда он нужен?
import type { ReactNode } from 'react';import { createPortal } from 'react-dom'; interface ModalProps { open: boolean; onClose: () => void;…Что выведется в консоль, когда пользователь нажмёт на кнопку, отрендеренную через портал?
import { createPortal } from 'react-dom'; function App() { return ( <div onClick={() => console.log('App div')}> <Popup /> </div> );} function Popup() { return createPortal( <button onClick={() => console.log('button')}>Open</button>, document.body, );}Как бы вы организовали папки в большом React-приложении?
src/ app/ providers, router, global styles pages/ route components: compose features, no logic features/ checkout/ api.ts…Проведите код-ревью этого компонента: какие проблемы вы видите и в каком порядке о них скажете?
function TeamMembers({ teamId, onSelect }: { teamId: string; onSelect: (user: User) => void }) { const [users, setUsers] = useState<User[]>([]); const [query, setQuery] = useState(''); const [visible, setVisible] = useState<User[]>([]); useEffect(() => { fetch(`/api/teams/${teamId}/users`).then((res) => res.json()).then(setUsers); }, []); useEffect(() => setVisible(users.filter((u) => u.name.includes(query))), [users, query]); return ( <div> <input value={query} onChange={(e) => setQuery(e.target.value)} /> {visible.map((u) => <div key={u.id} onClick={() => onSelect(u)}>{u.name}</div>)} </div> );}Как спроектировать переиспользуемый компонент, который работает и как контролируемый, и как неконтролируемый?
import { useState, type ReactNode } from 'react'; function useControllableState<T>(value: T | undefined, defaultValue: T, onChange?: (next: T) => void) { const [inner, setInner] = useState(defaultValue); const isControlled = value !== undefined; const current = isControlled ? value : inner;…Где ставить error boundary в приложении и как они работают вместе с Suspense и повтором?
import { Suspense, type ReactNode } from 'react';import { ErrorBoundary } from 'react-error-boundary';import { useLocation } from 'react-router'; function RouteShell({ children }: { children: ReactNode }) { const { pathname } = useLocation();…Как настроить мониторинг ошибок в продакшен-приложении на React, чтобы отчёты были читаемыми и по ним можно было действовать?
import * as Sentry from '@sentry/react';import { createRoot } from 'react-dom/client'; Sentry.init({ dsn: import.meta.env.VITE_SENTRY_DSN, release: import.meta.env.VITE_GIT_SHA, // ties every event to one deploy…Как не дать фичам импортировать внутренности друг друга и в чём подвохи barrel-файлов?
// eslint.config.jsexport default [ { files: ['src/**/*.{ts,tsx}'], rules: { 'no-restricted-imports': ['error', {…Когда монорепозиторий оправдан для React-проектов и как его настроить?
{ "name": "@acme/ui", "version": "0.0.0", "private": true, "type": "module", "exports": {…Как бы вы перевели большое приложение с React 18 на React 19 и что при этом обычно ломается?
# 1. React 18.3 is 18.2 plus a warning for every API React 19 removesnpm install react@18.3 react-dom@18.3# run the app and the tests, fix every warning # 2. Codemods for the removed APIs and for the type changesnpx codemod@latest react/19/migration-recipe…