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

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

В: Объясните концепцию «поднятия состояния вверх» в React.

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

import React, { useState } from 'react';

const ParentComponent = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

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

const ChildComponent = ({ count, increment }) => {
  return (
    <div>
      <button onClick={increment}>Increment</button>
      <p>Child Count: {count}</p>
    </div>
  );
};

В: Как React справляется с оптимизацией производительности и какие методы повышения производительности существуют?

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

import React, { useState, memo } from 'react';

// Regular functional component
const Item = ({ item }) => {
  console.log('Item rendered:', item);
  return <li>{item}</li>;
};

// Optimized functional component using React.memo
const MemoizedItem = memo(Item);

const App = () => {
  const [items, setItems] = useState(['Apple', 'Banana', 'Orange']);

  const addItem = () => {
    const newItem = prompt('Enter a new item:');
    setItems([...items, newItem]);
  };

  return (
    <div>
      <button onClick={addItem}>Add Item</button>
      <ul>
        {items.map((item, index) => (
          <MemoizedItem key={index} item={item} />
        ))}
      </ul>
    </div>
  );
};

В: Как вы справляетесь с управлением состоянием в больших приложениях React?

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

// Example using mobx
import { observable, action, makeObservable } from 'mobx';

class CounterStore {
  count = 0;

  constructor() {
    // To make the state observable and actions (methods) observable
    makeObservable(this, {
      count: observable,
      increment: action,
      decrement: action,
    });
  }

  increment() {
    this.count += 1;
  }

  decrement() {
    this.count -= 1;
  }
}

const counterStore = new CounterStore();
export default counterStore;

В: Что такое реквизиты рендеринга React и когда бы вы их использовали?

Render props — это шаблон проектирования, в котором prop компонента — это функция, которая возвращает элементы React. Это полезно, когда вы хотите разделить поведение между компонентами, не используя компоненты более высокого порядка или хуки.

// RenderPropsComponent.js
import React from 'react';

const RenderPropsComponent = ({ render }) => {
  const data = 'Hello, from RenderPropsComponent!';
  return (
    <div>
      <h2>Render Props Example</h2>
      {render(data)}
    </div>
  );
};

export default RenderPropsComponent;
// App.js
import React from 'react';
import RenderPropsComponent from './RenderPropsComponent';

const App = () => {
  const renderData = (data) => {
    return <p>{data}</p>;
  };

  return (
    <div>
      <h1>React Render Props Example</h1>
      <RenderPropsComponent render={renderData} />
    </div>
  );
};

export default App;

В: Объясните концепцию контролируемых и неконтролируемых компонентов в React.

Состояние контролируемых компонентов управляется React и обычно управляется через реквизиты. Неконтролируемые компоненты управляют своим собственным состоянием, часто через ссылки, и меньше зависят от управления состоянием React.

// Controlled component
import React, { useState } from 'react';

const ControlledInput = () => {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <div>
      <h2>Controlled Input Example</h2>
      <input type="text" value={inputValue} onChange={handleChange} />
      <p>Value: {inputValue}</p>
    </div>
  );
};

export default ControlledInput;
// Uncontrolled component
import React, { useRef } from 'react';

const UncontrolledInput = () => {
  const inputRef = useRef(null);

  const handleClick = () => {
    const value = inputRef.current.value;
    console.log('Input Value (uncontrolled):', value);
  };

  return (
    <div>
      <h2>Uncontrolled Input Example</h2>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Get Value</button>
    </div>
  );
};

export default UncontrolledInput;

В: Как React обрабатывает границы ошибок и как бы вы их реализовали?

Границы ошибок — это компоненты React, которые перехватывают ошибки JavaScript во время рендеринга, в методах жизненного цикла и в процессе рендеринга всего дерева компонентов. Вы можете реализовать их с помощью метода жизненного цикла componentDidCatch или с помощью метода static getDerivedStateFromError.

// Class component example
import React, { Component } from 'react';

class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = {
      hasError: false,
    };
  }

  componentDidCatch(error, errorInfo) {
    // You can log the error or do any custom error handling here
    console.error('Error caught:', error, errorInfo);
    this.setState({ hasError: true });
  }

  render() {
    if (this.state.hasError) {
      return <h2>Something went wrong. Please try again later.</h2>;
    }

    return this.props.children;
  }
}

class MyComponent extends Component {
  render() {
    if (this.props.shouldThrowError) {
      // Simulating an error by throwing an exception
      throw new Error('This is an intentional error for demo purposes.');
    }

    return <h1>Hello, React Error Boundaries!</h1>;
  }
}

const App = () => {
  return (
    <ErrorBoundary>
      <MyComponent shouldThrowError={false} />
    </ErrorBoundary>
  );
};

export default App;
// Functional component example
import React, { useState } from 'react';

const ErrorBoundary = ({ children }) => {
  const [hasError, setHasError] = useState(false);

  const static getDerivedStateFromError(error) {
    console.error('Error caught:', error);
    return { hasError: true };
  }

  if (hasError) {
    return <h2>Something went wrong. Please try again later.</h2>;
  }

  return children;
};

const MyComponent = ({ shouldThrowError }) => {
  if (shouldThrowError) {
    throw new Error('This is an intentional error for demo purposes.');
  }

  return <h1>Hello, React Error Boundaries!</h1>;
};

const App = () => {
  return (
    <ErrorBoundary>
      <MyComponent shouldThrowError={false} />
    </ErrorBoundary>
  );
};

export default App;

В: Как можно оптимизировать производительность рендеринга при работе со списками в React?

Чтобы оптимизировать производительность рендеринга со списками, используйте реквизит key для каждого элемента списка, используйте memo или PureComponent React для рендеринга элементов и рассмотрите возможность использования таких библиотек, как react-virtualized, для эффективного рендеринга больших списков.

Предоставьте уникальную ключевую опору для каждого элемента при отображении списка.

import React from 'react';

const MyList = ({ items }) => {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
};

Использование реагирующей заметки

import React from 'react';

const MyComponent = React.memo(({ prop1, prop2 }) => {
  console.log('Rendering MyComponent');
  return (
    <div>
      <p>Prop 1: {prop1}</p>
      <p>Prop 2: {prop2}</p>
    </div>
  );
});

useMemo и useCallback

// useMemo and useCallback can be used to memoize the results
// of expensive calculations or functions, avoiding recomputing
// them on every render.
import React, { useMemo, useCallback } from 'react';

const MyComponent = ({ data }) => {
  const processedData = useMemo(() => {
    // Some expensive data processing logic
    console.log('Data processing');
    return data.map((item) => item * 2);
  }, [data]);

  const handleClick = useCallback(() => {
    // Handle click using the processedData
    console.log('Processed data:', processedData);
  }, [processedData]);

  return (
    <div>
      <button onClick={handleClick}>Click Me</button>
    </div>
  );
};

В: Что такое порталы в React и как бы вы их использовали?

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

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React Portal Example</title>
</head>
<body>
  <div id="root"></div>
  <!-- The portal target element -->
  <div id="portal-root"></div>
</body>
</html>
// Modal.js
import React from 'react';
import ReactDOM from 'react-dom';

const Modal = ({ isOpen, onClose, children }) => {
  if (!isOpen) return null;

  return ReactDOM.createPortal(
    <div className="modal-overlay">
      <div className="modal">
        <button className="close-btn" onClick={onClose}>
          Close
        </button>
        {children}
      </div>
    </div>,
    document.getElementById('portal-root')
  );
};

export default Modal;
// App.js
import React, { useState } from 'react';
import Modal from './Modal';

const App = () => {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const handleOpenModal = () => {
    setIsModalOpen(true);
  };

  const handleCloseModal = () => {
    setIsModalOpen(false);
  };

  return (
    <div>
      <h1>React Portal Example</h1>
      <button onClick={handleOpenModal}>Open Modal</button>
      <Modal isOpen={isModalOpen} onClose={handleCloseModal}>
        <h2>Hello from the Modal!</h2>
        <p>This content is rendered using a portal.</p>
      </Modal>
    </div>
  );
};

export default App;

В: Как вы справляетесь с побочными эффектами в React и каковы некоторые распространенные варианты использования?

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

import React, { useState, useEffect } from 'react';

const SideEffectExample = () => {
  const [data, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // Simulating data fetching using a setTimeout
    const fetchData = () => {
      setTimeout(() => {
        const fakeData = [
          { id: 1, name: 'Item 1' },
          { id: 2, name: 'Item 2' },
          { id: 3, name: 'Item 3' },
        ];
        setData(fakeData);
        setIsLoading(false);
      }, 1500);
    };

    fetchData();

    // Cleanup function (equivalent to componentWillUnmount)
    return () => {
      console.log('Component will unmount');
      // Perform any cleanup, e.g., clear intervals, cancel subscriptions, etc.
    };
  }, []); // Empty dependency array ensures the effect runs only once (on mount)

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>Side Effect Example</h1>
      <ul>
        {data.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default SideEffectExample;

В: Что такое хуки React и чем они отличаются от компонентов класса?

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

// Functional Component using React Hooks
import React, { useState } from 'react';

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

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};
// Class Component
import React, { Component } from 'react';

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

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

  render() {
    const { count } = this.state;
    return (
      <div>
        <p>Count: {count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

В: Объясните, как работает контекстный API React и когда его полезно использовать.

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

// MyContext.js
import React, { createContext, useState } from 'react';

// Create a context
const MyContext = createContext();

// Create a context provider
const MyContextProvider = ({ children }) => {
  const [data, setData] = useState('Default value');

  return (
    <MyContext.Provider value={{ data, setData }}>
      {children}
    </MyContext.Provider>
  );
};

export { MyContext, MyContextProvider };
// ComponentA.js
import React, { useContext } from 'react';
import { MyContext } from './MyContext';

const ComponentA = () => {
  const { data, setData } = useContext(MyContext);

  return (
    <div>
      <h2>Component A</h2>
      <p>Data from context: {data}</p>
      <button onClick={() => setData('Updated value in Component A')}>
        Update Data
      </button>
    </div>
  );
};

export default ComponentA;
// ComponentB.js
import React, { useContext } from 'react';
import { MyContext } from './MyContext';

const ComponentB = () => {
  const { data, setData } = useContext(MyContext);

  return (
    <div>
      <h2>Component B</h2>
      <p>Data from context: {data}</p>
      <button onClick={() => setData('Updated value in Component B')}>
        Update Data
      </button>
    </div>
  );
};

export default ComponentB;
// App.js
import React from 'react';
import { MyContextProvider } from './MyContext';
import ComponentA from './ComponentA';
import ComponentB from './ComponentB';

const App = () => {
  return (
    <MyContextProvider>
      <div>
        <h1>React Context API Example</h1>
        <ComponentA />
        <ComponentB />
      </div>
    </MyContextProvider>
  );
};

export default App;

В: Что такое React Router и как вы обрабатываете маршрутизацию в приложении React?

React Router — популярная библиотека для обработки маршрутизации в приложениях React. Он предоставляет такие компоненты, как BrowserRouter и Route, для определения различных маршрутов и управления навигацией между ними.

// App.js
import React from 'react';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import Home from './Home';
import About from './About';
import Contact from './Contact';

const App = () => {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/contact">Contact</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/contact" component={Contact} />
        </Switch>
      </div>
    </Router>
  );
};

export default App;
// Home.js
import React from 'react';

const Home = () => {
  return <h2>Welcome to the Home page!</h2>;
};

export default Home;
// About.js
import React from 'react';

const About = () => {
  return <h2>This is the About page.</h2>;
};

export default About;
// Contact.js
import React from 'react';

const Contact = () => {
  return <h2>Contact us at [email protected]</h2>;
};

export default Contact;

В: Как вы выполняете рендеринг на стороне сервера (SSR) в React и каковы его преимущества?

Рендеринга на стороне сервера можно добиться с помощью таких библиотек, как Next.js или встроенный в React ReactDOMServer. Преимущества включают улучшенную поисковую оптимизацию, более быструю начальную загрузку страниц и лучшую производительность для пользователей с медленным подключением.

В: Как бы вы обрабатывали формы и проверку формы в React?

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

В: Объясните концепцию компонентов высшего порядка (HOC) в React и варианты их использования.

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

// withClickCounter.js
import React, { Component } from 'react';

const withClickCounter = (WrappedComponent) => {
  class WithClickCounter extends Component {
    constructor(props) {
      super(props);
      this.state = {
        count: 0,
      };
    }

    handleIncrement = () => {
      this.setState((prevState) => ({ count: prevState.count + 1 }));
    };

    render() {
      return (
        <WrappedComponent
          count={this.state.count}
          handleIncrement={this.handleIncrement}
          {...this.props}
        />
      );
    }
  }

  return WithClickCounter;
};

export default withClickCounter;
// MyComponent.js
import React from 'react';

const MyComponent = ({ name, count, handleIncrement }) => {
  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>Click count: {count}</p>
      <button onClick={handleIncrement}>Increment Count</button>
    </div>
  );
};

export default MyComponent;
// App.js
import React from 'react';
import MyComponent from './MyComponent';
import withClickCounter from './withClickCounter';

const EnhancedComponent = withClickCounter(MyComponent);

const App = () => {
  return <EnhancedComponent name="John" />;
};

export default App;

В: Как вы справляетесь с разделением кода и отложенной загрузкой в ​​приложении React?

Разделение кода и отложенная загрузка обычно достигаются с помощью компонентов React lazy и Suspense или с помощью динамических операторов import() в Webpack. Это помогает уменьшить начальный размер пакета и повысить производительность приложения.

В: В чем разница между поверхностным рендерингом и полным рендерингом при тестировании React?

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

В: Как вы интегрируете сторонние библиотеки или код, отличный от React, с компонентами React?

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

В: Каковы преимущества использования React по сравнению с другими интерфейсными фреймворками или библиотеками?

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

В: Объясните процесс согласования React и то, как он помогает с эффективными обновлениями.

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

Надеюсь, что эта статья предоставит полезную информацию о программировании на React. Всего наилучшего.