Оптимизация и реорганизация React‑компонентов

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

Короткий ответ

Что ответить на собеседовании

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

Подробный разбор

Ответ с пояснениями

Условие

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

// dataService.js
import { ClientType as _ClientType } from './root';

export function getData(state) {
  const response = fetch('/api/companies', {
    method: 'POST',
    body: JSON.stringify({
      id: state.client.id,
      type: _ClientType.company
    })
  });

  return response;
}

export const ClientType = _ClientType;

// component.jsx
import * as React from 'react';
import { getData, ClientType } from './dataService';

function Component(props) {
  const { store } = props;
  const [items, setItems] = React.useState([]);

  React.useEffect(() => {
    (async () => {
      const response = getData(store.getState());
      const data = await (await response).json();
      setItems(data.items);
    })();
  }, []);

  return (
    <div>
      {items.map((item) => (
        <div className={`item item_type_${item.type}`} key={item.id}>
          {item.type === ClientType.person ? (
            <span>{item.name}</span>
          ) : (
            <span>Компания {item.id}</span>
          )}
          <button onClick={() => { console.log(item.id); }}>choose</button>
        </div>
      ))}
    </div>
  );
}

export default Component;

// root.jsx
import * as React from 'react';
import Component from './component';
import store from './store';

export const ClientType = {
  'company': 'company',
  'person': 'person',
};

function Root() {
  return (
    <Component store={store} />
  );
}

export default Root;

// app.jsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Root from './root';

ReactDOM.render(<Root />, document.querySelector('#app'));

Ответ

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

Сейчас dataService импортирует root, root — component, а component — dataService: это ненужная циклическая зависимость. Передача всего store.getState() также связывает сетевой слой со структурой хранилища.

async function getCompanies(clientId, signal) {
  const response = await fetch('/api/companies', {
    method: 'POST', signal,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ id: clientId, type: 'company' })
  });
  if (!response.ok) throw new Error('Ошибка загрузки');
  const data = await response.json();
  return data.items;
}

Получайте clientId через реактивную подписку на store и ставьте его в зависимости эффекта. В cleanup отменяйте запрос и не применяйте устаревший результат. Для session API добавьте предусмотренную сервером CSRF-защиту; сам заголовок JSON её не заменяет. Инициализацию React обновляйте под фактическую версию проекта, а не как часть изменения бизнес-логики.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее