Перейти к содержимому
На этой странице

Состояние, пропсы и контекст

Все темы React Developer

Подтемы:

Что такое “состояние” (state) компонента в React?

Состояние хранит данные компонента между рендерами. В классовом компоненте state является объектом; значение состояния, созданного useState, может иметь любой тип.

В классовом компоненте состояние задают в constructor или поле state и обновляют через setState. В функциональном используют useState или useReducer. Обновление ставится в очередь; новое значение доступно следующему рендеру.

Пример:

import React, { Component } from "react";

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0, // Начальное состояние
    };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Счетчик: {this.state.count}</p>
        <button onClick={this.increment}>Увеличить</button>
      </div>
    );
  }
}

export default Counter;

В этом примере компонент Counter имеет состояние count, которое обновляется при клике на кнопку. При вызове setState(), React обновит состояние и перерендерит компонент, отображая новое значение count.


Как обновить состояние компонента?

В классовом компоненте setState принимает объект обновлений или функцию от предыдущего состояния и поверхностно объединяет результат со state. В функциональном компоненте setter из useState принимает следующее значение или функцию от предыдущего значения и заменяет его целиком. Состояние нельзя изменять напрямую.

Пример использования setState():

import React, { Component } from "react";

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  increment = () => {
    // Обновление состояния с использованием объекта
    this.setState({ count: this.state.count + 1 });
  };

  decrement = () => {
    // Обновление состояния с использованием функции
    this.setState((prevState) => {
      return { count: prevState.count - 1 };
    });
  };

  render() {
    return (
      <div>
        <p>Счетчик: {this.state.count}</p>
        <button onClick={this.increment}>Увеличить</button>
        <button onClick={this.decrement}>Уменьшить</button>
      </div>
    );
  }
}

export default Counter;

В данном примере increment() и decrement() обновляют состояние count с помощью setState(). Важно использовать функции при обновлении состояния, особенно если новое состояние зависит от предыдущего состояния, чтобы избежать проблем с асинхронностью.


Что такое пропсы (props) в React?

“Пропсы” (props) в React - это механизм передачи данных от родительского компонента к дочернему. Они представляют собой атрибуты, которые задаются при создании компонента и не могут быть изменены самим компонентом, который их получает. Пропсы используются для передачи информации о состоянии или конфигурации компонента.

Пример использования пропсов:

import React from "react";

function Welcome(props) {
  return <h1>Привет, {props.name}!</h1>;
}

const App = () => {
  return <Welcome name="Алиса" />;
};

export default App;

В этом примере компонент Welcome принимает пропс name и использует его для вывода персонализированного приветствия. Компонент App передает значение “Алиса” в пропс name компонента Welcome.

Пропсы передаются в виде объекта и доступны как свойства (props) внутри дочернего компонента.

Использование пропсов позволяет создавать более гибкие и переиспользуемые компоненты, так как можно настраивать их поведение и отображение извне.


В чем разница между состоянием и пропсами?

Состояние (state) и пропсы (props) - это два основных концепта в React, используемые для управления данными в компонентах. Они имеют разные цели и характеристики:

Состояние ( state ):
  1. Состояние - это внутренние данные компонента, которые могут изменяться во время выполнения.

  2. Определяется и управляется самим компонентом, в котором оно находится.

  3. Изменение состояния вызывает перерендеринг компонента, чтобы отобразить новое состояние.

  4. Доступно только для компонента, в котором было определено состояние.

  5. Обновляется через setState в классе, setter из useState или dispatch из useReducer в функциональном компоненте.

Пропсы ( props ):
  1. Пропсы - это данные, передаваемые от родительского компонента к дочернему компоненту.

  2. Нельзя изменить пропсы внутри дочернего компонента. Они считаются “только для чтения”.

  3. Пропсы служат для настройки и передачи данных в компоненты.

  4. Используются для связи между различными компонентами и передачи информации вниз по иерархии.

  5. При рендере родителя дочерний компонент обычно рендерится с новыми пропсами. memo может пропустить рендер, если пропсы не изменились.

Вкратце, состояние предназначено для хранения и управления изменяющимися данными внутри компонента, тогда как пропсы предназначены для передачи данных от родительского компонента к дочернему. Оба этих концепта помогают создавать динамичные и переиспользуемые интерфейсы в React приложениях.


Как обновить состояние компонента после изменения props?

В React существует несколько способов обновления состояния компонента после изменения его props. Это может потребоваться, когда компонент зависит от входящих props и должен реагировать на их изменения. Вот несколько подходов:

  1. componentDidUpdate(prevProps) : Метод componentDidUpdate()  вызывается после обновления компонента. Вы можете сравнить предыдущие и текущие props с помощью параметра prevProps и  this.props, и при необходимости обновить состояние:

    componentDidUpdate(prevProps) {
      if (this.props.someProp !== prevProps.someProp) {
        this.setState({ someState: newValue });
      }
    }
  2. getDerivedStateFromProps(nextProps, prevState) : Этот статический метод вызывается перед рендерингом и каждый раз, когда происходит обновление props. Вы можете вернуть новое состояние на основе новых props:

    static getDerivedStateFromProps(nextProps, prevState) {
      if (nextProps.someProp !== prevState.prevPropValue) {
        return { someState: newValue };
      }
      return null;
    }
  3. useState с useEffect : Если вы используете функциональные компоненты, вы можете использовать useState для хранения состояния и  useEffect для реагирования на изменения props:

    import React, { useState, useEffect } from "react";
    
    function MyComponent(props) {
      const [state, setState] = useState(initialState);
    
      useEffect(() => {
        if (props.someProp !== state.someState) {
          setState({ someState: newValue });
        }
      }, [props.someProp]);
    
      //...
    }

Не копируйте props в state без необходимости: вычисляйте производные значения во время рендера. Для полного сброса состояния можно изменить key компонента. getDerivedStateFromProps нужен лишь в редких случаях; Effect предназначен прежде всего для синхронизации с внешними системами. Примеры выше схематичны: initialState и newValue должны быть определены, а отслеживаемое предыдущее значение пропса нужно обновлять вместе с состоянием.


Как передать данные между компонентами вверх и вниз по иерархии?

В React данные могут передаваться между компонентами вверх и вниз по иерархии с использованием пропсов (props) и колбэков (callback функций). Вот как это работает:

Передача данных вниз по иерархии (от родителя к дочернему компоненту):

  1. Пропсы (props): Родительский компонент передает данные своему дочернему компоненту через пропсы. Дочерний компонент может получить доступ к этим данным как свойства (props).

Пример:

// Родительский компонент
import React from "react";
import ChildComponent from "./ChildComponent";

const ParentComponent = () => {
  const data = "Данные для дочернего компонента";

  return <ChildComponent dataProp={data} />;
};

// Дочерний компонент
import React from "react";

const ChildComponent = (props) => {
  return <p>{props.dataProp}</p>;
};

export default ChildComponent;

Передача данных вверх по иерархии (от дочернего компонента к родителю):

  1. Колбэки (callback функции): Родительский компонент передает функцию в качестве пропса дочернему компоненту. Дочерний компонент может вызвать эту функцию, передавая ей данные обратно вверх по иерархии.

Пример:

// Родительский компонент
import React, { useState } from "react";
import ChildComponent from "./ChildComponent";

const ParentComponent = () => {
  const [receivedData, setReceivedData] = useState("");

  const handleDataChange = (data) => {
    setReceivedData(data);
  };

  return (
    <div>
      <p>Полученные данные: {receivedData}</p>
      <ChildComponent onDataChange={handleDataChange} />
    </div>
  );
};

// Дочерний компонент
import React from "react";

const ChildComponent = (props) => {
  const sendDataToParent = () => {
    props.onDataChange("Данные от дочернего компонента");
  };

  return <button onClick={sendDataToParent}>Отправить данные</button>;
};

export default ChildComponent;

Это позволяет дочернему компоненту воздействовать на данные и состояние родительского компонента.

Используя этот подход, вы можете эффективно передавать и обновлять данные между компонентами вверх и вниз по иерархии.


Что такое “подъем состояния” (lifting state up)?

“Подъем состояния” (lifting state up) - это паттерн в React, который предполагает перемещение состояния из дочерних компонентов в родительские компоненты, чтобы разделять и управлять состоянием на более высоком уровне и передавать его через пропсы.

Этот подход особенно полезен, когда несколько компонентов должны иметь доступ к одному и тому же состоянию или когда состояние должно быть синхронизировано между разными частями приложения.

Пример с подъемом состояния:

import React, { useState } from "react";

const TemperatureInput = ({ scale, temperature, onTemperatureChange }) => {
  return (
    <fieldset>
      <legend>Введите температуру в градусах {scale}:</legend>
      <input
        value={temperature}
        onChange={(e) => onTemperatureChange(e.target.value)}
      />
    </fieldset>
  );
};

const Calculator = () => {
  const [celsius, setCelsius] = useState("");
  const [fahrenheit, setFahrenheit] = useState("");

  const handleCelsiusChange = (value) => {
    setCelsius(value);
    setFahrenheit((value * 9) / 5 + 32);
  };

  const handleFahrenheitChange = (value) => {
    setFahrenheit(value);
    setCelsius(((value - 32) * 5) / 9);
  };

  return (
    <div>
      <TemperatureInput
        scale="C"
        temperature={celsius}
        onTemperatureChange={handleCelsiusChange}
      />
      <TemperatureInput
        scale="F"
        temperature={fahrenheit}
        onTemperatureChange={handleFahrenheitChange}
      />
    </div>
  );
};

export default Calculator;

В этом примере компонент Calculator поднимает состояние температур из TemperatureInput компонентов. При изменении температуры в одном из вводов, состояние поднимается в родительский компонент Calculator, который затем обновляет состояние для другого ввода, обеспечивая синхронизацию температур в обеих шкалах.


Что такое “нормализация состояния” (state normalization) в контексте управления состоянием приложения?

Нормализация состояния (state normalization) - это паттерн управления состоянием, который используется для организации данных в хранилище таким образом, чтобы обеспечить эффективное хранение, обновление и доступ к данным в Redux или других системах управления состоянием.

Основная идея нормализации состоит в том, чтобы хранить данные в нормализованной форме, где каждый тип данных хранится в отдельной коллекции (таблице), и используются ссылки между различными коллекциями для устранения дублирования данных и облегчения обновления.

Пример: Предположим, у нас есть список постов и список комментариев к этим постам. Вместо хранения комментариев внутри каждого поста (что может привести к дублированию данных), мы можем создать две коллекции: “посты” и “комментарии”, и использовать идентификаторы постов в комментариях для установления связи между ними.

Преимущества нормализации состояния:

  1. Экономия места: Дублирование данных уменьшается, так как одни и те же данные не хранятся в нескольких местах.

  2. Легкость обновления: Изменение данных в одной коллекции автоматически отражается в других, где эти данные используются.

  3. Быстрый доступ: Поиск, фильтрация и доступ к данным ускоряются, так как данные разделены на более мелкие коллекции.

  4. Прозрачность: Структура хранилища становится более легко понимаемой и отслеживаемой.

В то время как нормализация может помочь в оптимизации и управлении состоянием, она также добавляет сложности в логику обновления данных и может потребовать дополнительной работы при выборе данных для отображения в компонентах. Вам стоит выбрать подход в зависимости от размера и сложности вашего приложения.


Как управлять состоянием между компонентами, не имеющими близкой связи?

Существует несколько методов для управления состоянием между компонентами, которые не имеют прямой связи. Вот некоторые из них:

  1. Поднятие состояния ( Lifting State Up ): Вы можете поднять состояние до ближайшего общего родительского компонента, который имеет доступ и к одному, и к другому компоненту. Затем передавайте это состояние как пропсы в каждый компонент. Этот подход особенно полезен, когда компоненты имеют общий родительский компонент, но не имеют прямой связи друг с другом.

  2. Контекст ( Context API ): Используйте Context API, который позволяет передавать данные глубоко в дерево компонентов без явной передачи пропсов через все уровни. Создайте контекст и оберните ваше дерево компонентов этим контекстом. Таким образом, компоненты смогут получать доступ к данным из контекста, даже если они не находятся в прямой иерархии.

  3. Глобальное состояние ( Global State ): Используйте библиотеки управления состоянием, такие как Redux или MobX, чтобы создать глобальное хранилище данных, доступное для всех компонентов. Это особенно полезно, если состояние нужно между компонентами, которые находятся далеко друг от друга в дереве компонентов.

  4. Событийная система: Реализуйте свою событийную систему, которая позволит компонентам подписываться на определенные события и передавать данные. Это можно сделать с помощью сторонних библиотек или самостоятельно.

  5. RESTful API: Если ваши компоненты общаются с сервером, вы можете использовать RESTful API для обмена данными между ними. Компоненты могут получать и отправлять данные через API.

  6. Библиотеки для управления состоянием: В зависимости от вашего опыта и требований, вы также можете рассмотреть использование библиотек управления состоянием, таких как Recoil, Zustand и других.

Выбор метода будет зависеть от конкретных требований вашего приложения, его архитектуры и сложности взаимодействия между компонентами.


Какие популярные библиотеки для управления состоянием вы знаете, помимо встроенного useState?

Популярные библиотеки для управления состоянием в React:

  1. Redux:

    • Централизованное хранилище состояния с предсказуемым поведением.

    • Пример использования:

      import { createStore } from 'redux';
      import { Provider } from 'react-redux';
  2. MobX:

    • Реактивное управление состоянием с фокусом на наблюдаемых данных и реакциях.

    • Пример использования:

      import { observable } from 'mobx';
      import { observer } from 'mobx-react';
  3. Recoil:

    • Recoil использует атомы и селекторы, но его репозиторий архивирован в январе 2025 года. Это исторический пример, а не рекомендация для нового проекта.

    • Пример использования:

      import { RecoilRoot, atom, useRecoilState } from 'recoil';
  4. Zustand:

    • Легковесная и гибкая библиотека для управления состоянием.

    • Пример использования:

      import { create } from 'zustand';
  5. Context API:

    • Встроенный механизм для управления глобальным состоянием с помощью контекста.

    • Пример использования:

      import { createContext, useContext } from 'react';

Помимо встроенного useState, для управления состоянием в React популярны библиотеки Redux, MobX, Recoil, Zustand, а также встроенный Context API.


Какие паттерны использования Redux вы знаете?

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

  1. Действия (Actions):

    • Описывают изменения состояния через типы и полезную нагрузку.

    • Пример:

      const increment = () => ({ type: 'INCREMENT' });
  2. Редьюсеры (Reducers):

    • Функции, которые описывают, как состояние изменяется в ответ на действия.

    • Пример:

      const counter = (state = 0, action) => {
        switch (action.type) {
          case 'INCREMENT':
            return state + 1;
          default:
            return state;
        }
      };
  3. Хранилище (Store):

    • Хранит состояние приложения и предоставляет методы для доступа к состоянию и отправки действий.

    • Пример:

      import { createStore } from 'redux';
      const store = createStore(counter);
  4. Контейнерные компоненты (Container Components):

    • Соединяют компоненты React с Redux-хранилищем с помощью connect.

    • Пример:

      import { connect } from 'react-redux';
      
      const mapStateToProps = (state) => ({ count: state });
      const mapDispatchToProps = { increment };
      
      export default connect(mapStateToProps, mapDispatchToProps)(CounterComponent);
  5. Thunk Middleware:

    • Позволяет писать действия, которые возвращают функции вместо объектов, для работы с асинхронными операциями.

    • Пример:

      import { thunk } from 'redux-thunk';
      import { applyMiddleware, createStore } from 'redux';
      
      const store = createStore(rootReducer, applyMiddleware(thunk));
  6. Селекторы (Selectors):

    • Функции для выборки данных из состояния, повышают читаемость и повторное использование кода.

    • Пример:

      const getCount = (state) => state.counter;

Популярные паттерны использования Redux включают действия, редьюсеры, хранилище, контейнерные компоненты, thunk middleware и селекторы. Эти паттерны помогают структурировать и управлять состоянием приложения эффективно.


Какие альтернативы Redux для управления состоянием в React-приложениях?

Альтернативы Redux для управления состоянием в React-приложениях:

  1. MobX:

    • Реактивное управление состоянием с акцентом на наблюдаемые данные и автоматические реакции.

    • Пример:

      import { observable, action } from 'mobx';
      import { observer } from 'mobx-react';
  2. Recoil:

    • Recoil использует атомы и селекторы, но его репозиторий архивирован в январе 2025 года. Это исторический пример, а не рекомендация для нового проекта.

    • Пример:

      import { RecoilRoot, atom, useRecoilState } from 'recoil';
  3. Zustand:

    • Легковесная и гибкая библиотека для управления состоянием.

    • Пример:

      import { create } from 'zustand';
      const useStore = create(set => ({
        count: 0,
        increment: () => set(state => ({ count: state.count + 1 }))
      }));
  4. Context API:

    • Встроенный механизм для управления глобальным состоянием с помощью контекста.

    • Пример:

      import { createContext, useContext, useState } from 'react';
      const MyContext = createContext();
      const MyProvider = ({ children }) => {
        const [state, setState] = useState(0);
        return <MyContext.Provider value={{ state, setState }}>{children}</MyContext.Provider>;
      };
  5. XState:

    • Управление состоянием с использованием конечных автоматов и диаграмм состояний.

    • Схематичный пример старого API XState 4. В XState 5 используют createMachine или setup; useMachine вызывают внутри компонента или пользовательского хука:

      import { Machine } from 'xstate';
      import { useMachine } from '@xstate/react';
      const toggleMachine = Machine({ /* состояние машины */ });
      const [state, send] = useMachine(toggleMachine);
  6. React Query:

    • Специализируется на управлении состоянием данных, извлекаемых из серверов.

    • Пример для React Query 3; useQuery вызывается внутри компонента или пользовательского хука. В TanStack Query 5 используется объект параметров:

      import { useQuery } from 'react-query';
      const { data, error, isLoading } = useQuery('data', fetchData);

Альтернативы Redux для управления состоянием в React-приложениях включают MobX, Recoil, Zustand, Context API, XState и React Query. Эти библиотеки и инструменты предлагают разные подходы и функциональные возможности для управления состоянием.


Когда useReducer лучше useState?

useReducer удобнее, когда состояние меняется через несколько связанных переходов, следующие значения зависят от предыдущих, а правила обновления разбросались по обработчикам. Reducer принимает state и action и возвращает новое состояние, поэтому переходы можно читать и тестировать как чистую функцию. Это полезно для сложной формы, wizard или state machine. Для одного независимого boolean или строки useState проще. Reducer не делает состояние глобальным и не уменьшает render автоматически; его ценность состоит в явной модели переходов. Побочные эффекты выполняют вне reducer.


По каким признакам приложению нужен внешний стейт-менеджер?

Внешний state manager оправдан, если одно клиентское состояние читают и изменяют далёкие части дерева, нужны сложные переходы, middleware, time-travel или единая диагностика. До выбора отделяют server state: запросы, кеш, дедупликацию и инвалидирование лучше часто решает специализированная библиотека. Локальные поля формы, hover и открытие модалки оставляют рядом с компонентом. Context подходит редко меняющимся зависимостям, но частые широкие обновления требуют аккуратного разделения. Решение принимают по владельцу данных, частоте обновлений и реальным проблемам отладки. Дополнительная инфраструктура должна окупать сериализацию, boilerplate и обучение команды.


Что такое контекст (context) в React и для чего он используется?

Контекст ( Context ) — это механизм, который позволяет передавать данные через дерево компонентов без необходимости передавать пропсы на каждом уровне.

Основные характеристики:

  1. Обмен данными между компонентами:

    • Используется для обмена данными между компонентами, которые находятся на разных уровнях вложенности.
  2. Создание и использование контекста:

    • Создается с помощью React.createContext.

    • Обеспечивает доступ к данным через компоненты Provider и Consumer.

Пример:

import React, { createContext, useContext } from "react";

const MyContext = createContext();

const MyProvider = ({ children }) => {
  const value = "Hello, World!";
  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
};

const MyComponent = () => {
  const value = useContext(MyContext);
  return <div>{value}</div>;
};

const App = () => (
  <MyProvider>
    <MyComponent />
  </MyProvider>
);

export default App;

Контекст в React используется для передачи данных через дерево компонентов, избегая необходимости прокидывать пропсы на каждом уровне.


Как работает механизм “контекста” (context) для передачи данных?

Контекст ( Context ) — это механизм, который позволяет передавать данные через дерево компонентов без необходимости передавать пропсы на каждом уровне.

Основные шаги:

  1. Создание контекста:

    • Создайте контекст с помощью React.createContext.
    const MyContext = React.createContext();
  2. Обертка компонентов в Provider:

    • Используйте компонент Provider для обертки тех компонентов, которые должны иметь доступ к контексту. Укажите значение, которое должно быть передано через контекст.
    <MyContext.Provider value={/* значение */}>
      {/* дочерние компоненты */}
    </MyContext.Provider>
  3. Потребление контекста:

    • Компоненты, которые должны получать данные из контекста, могут использовать компонент Consumer или хук useContext.
    // Использование хука useContext
    const value = useContext(MyContext);

Пример:

import React, { createContext, useContext } from "react";

// Создание контекста
const MyContext = createContext();

// Компонент Provider
const MyProvider = ({ children }) => {
  const value = "Hello, World!";
  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
};

// Компонент Consumer с хуком useContext
const MyComponent = () => {
  const value = useContext(MyContext);
  return <div>{value}</div>;
};

// Основное приложение
const App = () => (
  <MyProvider>
    <MyComponent />
  </MyProvider>
);

export default App;

Контекст в React позволяет передавать данные через дерево компонентов с помощью компонентов Provider и Consumer, а также хука useContext, упрощая обмен данными между компонентами на разных уровнях вложенности.


Что такое “передача данных через контекст” (context passing) в React?

Передача данных через контекст — это механизм, который позволяет передавать данные напрямую через дерево компонентов без необходимости передавать пропсы на каждом уровне.

Основные шаги:

  1. Создание контекста:

    • Создайте контекст с помощью React.createContext.
    const MyContext = React.createContext();
  2. Использование Provider:

    • Оберните дерево компонентов в MyContext.Provider и передайте значение контекста.
    <MyContext.Provider value={/* значение */}>
      {/* дочерние компоненты */}
    </MyContext.Provider>
  3. Использование Consumer или useContext:

    • Компоненты, которые должны получать данные из контекста, используют MyContext.Consumer или хук useContext.
    const value = useContext(MyContext);

Пример:

import React, { createContext, useContext } from "react";

// Создание контекста
const MyContext = createContext();

// Компонент Provider
const MyProvider = ({ children }) => {
  const value = "Hello, World!";
  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
};

// Компонент Consumer с хуком useContext
const MyComponent = () => {
  const value = useContext(MyContext);
  return <div>{value}</div>;
};

// Основное приложение
const App = () => (
  <MyProvider>
    <MyComponent />
  </MyProvider>
);

export default App;

Передача данных через контекст позволяет эффективно передавать данные через дерево компонентов, избегая необходимости пропс-дриллинга (передачи пропсов на каждом уровне).

Собеседования: React

Смотри записи интервью, узнай, какие вопросы задают и как отвечают кандидаты.

Вопросы и ответы

Не нашли ответ? Напишите мне в чат. Я делаю Шпаргалку и сам отвечаю на сообщения. Расскажите, что не работает или чего вам не хватает. Может, смогу сразу взять это в работу.

Откуда взяты вопросы?

Из реальных собеседований. Основой подборки стал опыт Вадима Новосёлова: он проходил интервью и записывал вопросы. Подробнее о материалах.

Насколько эти вопросы актуальны?

Эти вопросы встречались нам на реальных собеседованиях в 2025 году. Мы регулярно проходим собеседования и пополняем подборку новыми вопросами. Основы профессии и ключевые технологии остаются востребованными годами, а детали конкретных инструментов и версий стоит сверять с текущей документацией.

На какой уровень рассчитана подборка?

Мы проходили собеседования на вакансии уровня Middle+, а иногда и на Senior-позиции. Вопросы из этих интервью вошли в подборку. Направления работы: React-разработчик, Frontend-разработчик. Глубина обсуждения зависит от вакансии: будь готов объяснить основную идею, привести практический пример и разобрать ограничения и альтернативы решения.

Этот вопрос точно будет на моём собеседовании?

Гарантии нет: набор вопросов зависит от компании, задач команды, уровня вакансии и самого интервьюера. Эти вопросы уже встречались на реальных собеседованиях, но на твоём интервью ту же тему могут проверить другой формулировкой, практической задачей или обсуждением твоего опыта. Используй подборку, чтобы разобраться в теме: объясняй идею своими словами, приводи примеры и готовься обсудить ограничения и альтернативы решения. Так будет проще ответить и на знакомый вопрос, и на неожиданные уточнения.