Всем привет! Меня зовут Олег и я fullstack-программист в компании Тензор. Опыт в разработке, без малого, 20 лет (как-то раз батя спаял на кухне ZX Spectrum и все заверте..., сам не понял как так вышло). В данный момент являюсь тимлидом собственной команды разработчиков, которая периодически нуждается в пополнении толковыми программистами.

Как и многие руководители, я активно принимаю участие в подборе сотрудников для себя и помогаю на собесах коллегам соседних отделов.

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

Если вы тоже в вечном поиске классных фронтендеров или сами часто проходите собесы - велком в эту статью :)

Я предлагаю написать hook для загрузки данных. Примерно так:

Напиши React hook с названием useFetch, который получает на вход URL для загрузки и возвращает полученные данные. Для загрузки данных можно использовать любое API, даже собственно придуманное. Для простоты считаем, что по указанному адресу будет JSON, загружаем методом GET, никаких других методов, заголовков и типов данных не требуется. Импорты можно не писать.

Дополнительно даю такой "шаблон" решения задачи:

function useFetch(url) {
  // TODO
}

// usage
function Component({ url }) {
  ........ = useFetch(url);

  return <>
	...
  </>
}

Я намеренно не даю информации как именно надо вернуть данные, предлагаю кандидату самостоятельно спроектировать API этого hook'а.

Задачка "многослойная". Можно начать с простого решения:

function useFetch(url) {
	const [data, setData] = useState(null);

	useEffect(() => {
		fetch(url)
			.then((res) => res.json())
			.then((respData) => setData(respData));
	}, []);

	return data;
}

Это необходимый минимум с которого надо начинать. Иногда даже это не удается получить. Соискатель пытается вернуть из hook Promise и "зарендерить" его в надежде на чудо, пытается обмазать результат хука async/await и т.д. Иногда вся логика загрузки оказывается в компоненте - тут я прошу все это инкапсулировать внутри hook.

Дальше нужно осознать, что в эффекте не хватает зависимости. Если url изменится, то запроса данных не произойдет.

function useFetch(url) {
	const [data, setData] = useState(null);

	useEffect(() => {
		setData(null); // не забыть сбросить данные перед загрузкой
		fetch(url)
			.then((res) => res.json())
			.then((respData) => setData(respData));
	}, [url]); // <-- не забыть зависимость

	return data;
}

На этом этапе можно остановиться, и попросить предложить варианты, как можно улучшить этот hook. Хочется что бы кандидат как минимум предложил обработать ошибку и вернуть статус загрузки

function useFetch(url) {
	const [data, setData] = useState(null);
	const [isLoading, setIsLoading] = useState(false);
	const [error, setError] = useState(null);

	useEffect(() => {
		// не забыть все сбросить
		setIsLoading(true);
		setData(null);
		setError(null);
		fetch(url)
			.then((res) => res.json())
			.then((respData) => setData(respData))
			.catch((e) => setError(e)) // не забыть поймать ошибку
			.finally(() => setIsLoading(false)); // не забыть сбросить статус загрузки
	}, [url]); 

	return [data, isLoading, error];
}

Следующий уровень сложности - понять, что в этой реализации возможен race condition. Если мы последовательно запросим два URL, и так получится, что первый будет отвечать долго, а второй быстро, то мы получим сперва результат от второго адреса, а затем от первого. В итоге пользователь увидит устаревший результат. Далеко не все добираются до этого самостоятельно. Можно подсказать, предложить подумать, как будут развиваться события, если запросы будут отвечать за разное время, один быстрее, другой медленнее.

Решения могут быть через AbortController (в случае fetch или в случае использования axios), но достаточно реализовать самый простой способ - с помощью локальной переменной

function useFetch(url) {
   const [data, setData] = useState(null);
   const [isLoading, setIsLoading] = useState(false);
   const [error, setError] = useState(null);

   useEffect(() => {
      // флаг отмены
      let cancelled = false;

      setIsLoading(true);
      setData(null);
      setError(null);
      fetch(url)
         .then((res) => res.json())
         .then((respData) => {
            if (!cancelled) setData(respData);
         })
         .catch((e) => {
            if (!cancelled) setError(e);
         })
         .finally(() => {
            if (!cancelled) setIsLoading(false);
         });

      return () => {
         // выставим признак того, что запрос отменен
         cancelled = true;
      };
   }, [url]);

   return [data, isLoading, error];
}

Вот такой вариант я считаю "идеальным" (обсудим в комментариях, что можно еще улучшить?).

Задачка позволяет проверить, как кандидат понимает устройство рендеринга React, как устроено хранение состояния, когда происходят перерисовки, как заставить компонент перерисоваться в ответ на асинхронное событие, как устроена "очистка (cleanup) эффекта", как работают сайд-эффекты.

Комментарии (46)


  1. veezex
    10.01.2024 15:53
    +2

    Попробуйте вместо использования флага cancelled использовать AbortController https://developer.mozilla.org/en-US/docs/Web/API/AbortController


    1. Olegas Автор
      10.01.2024 15:53

      Кстати, отличное замечание! Ведь AbortContoller есть не только как часть fetch или axios (о чем упомянуто в статье), а и как вполне самостоятельная единица. С другой стороны, если его использовать самостоятельно (на в паре с fetch/axios), по сути этот тот же булевский флаг.


      1. veezex
        10.01.2024 15:53
        +1

        Все же AbortController немного по другому действует, если посмотрите в консоли браузера - controller.abort() отменяет запрос к бэкэнду, а то время как реализация с флагом просто игнорирует его. Я к тому что использование AbortController может позволить бэку более эффективно использовать свои ресурсы (ну и траффик между фронтом и бэком немного сэкономим). Ну может это было очевидно, просто я недавно как раз решал похожую задачу с реализацией автокомплита в инпуте и там это было важно


        1. Olegas Автор
          10.01.2024 15:53

          Так я же говорю:

          Решения могут быть через AbortController (в случае fetch или в случае использования axios), но достаточно реализовать самый простой способ - с помощью локальной переменной

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

          Безусловно, широкий кругозор соискателя (знание AbortController) будет в плюс, но достаточно простого решения.

          Кстати, на тему "отмены" запроса к бэку. Совершенно верно, использование правильного механизма отмены дает больше возможностей "сэкономить". Но, с точки зрения запроса от клиента к серверу, его нельзя "отменить". Можно только разорвать соединение. А уж как этот разрыв соединения будет обработан серверной стороной, это уже зависит от конкретных используемых инструментов на бэке и какая именно задача выполнялась (запрос к базе, чтение файла и т.п.).


          1. MaxLevs
            10.01.2024 15:53

            Как минимум понимание, зачем нужна отмена запроса к беку - это следствие осознания, что на фронте все не заканчивается, а только начинается.
            Отмена ненужных запросов очень критична для бекенда. Бек не знает, нужен результат метода или уже нет. Его попросили - он сделал. Но запросы бывают тяжёлыми. Остаётся только полагаться на фронт: чтоб сказал явно, если уже что-то не нужно.
            Условному соискателю-фронту потом с банком работать. А если он потом будет выдавать "я сделал у себя, как надо, это всё бек", то возникнут вопросы к лиду.


            1. Olegas Автор
              10.01.2024 15:53

              А как это "сказал явно"? С точки зрения протокола HTTP как можно "явно" отменить запрос?


              1. MaxLevs
                10.01.2024 15:53

                Вот. Правильный вопрос для собеседования. Идёт после вопроса "а зачем вообще отменять". И перед вопросом "какие есть варианты имплементации?"


  1. fasoGOda
    10.01.2024 15:53
    +4

    Я конечно извиняюсь за душнилство, но в java-script, то есть в React по сути, не может быть race condition, так как он однопоточен. Ваша же ссылка об этом и говорит. Это можно назвать, особенностями асинхронного взаимодействия, или может есть другое название, я не знаю. Но это не race condition


    1. Olegas Автор
      10.01.2024 15:53
      +2

      Конечно, JavaScript однопоточный, но вот приложение или система в целом (JavaScript на клиенте + асинхронный HTTP-транспорт + удаленный сервер) вполне может быть рассмотрена как "многопоточная", где однопоточный источник может породить несколько процессов, которые в рамках всей системы будут выполняться параллельно и вполне себе создавать race condition. Так что при всем уважении, термин я оставлю ;)


      1. gsaw
        10.01.2024 15:53

        Мне кажется тоже, что это не состояние гонки. Состояние гонки это когда параллельно какие то данные обновляются/читаются, причем могут выйти непредвиденные результаты.

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

        Это просто уборка за собой, если результат уже не нужен. Причем это хак, с флагом, с тех времён, когда AbortController не был стандартом. Сам пользуюсь, потому, что проще и привык :)


        1. Olegas Автор
          10.01.2024 15:53

          Это именно гонка.

          Состояние гонки это когда параллельно какие то данные обновляются/читаются, причем могут выйти непредвиденные результаты.

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

          Многие помнят что "отмена" эффекта нужна при размонтировании компонента. Но многие же забывают, что "отмена" эффекта происходит также и при смене значения зависимостей.


          1. fasoGOda
            10.01.2024 15:53
            -3

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


            1. mrsimb
              10.01.2024 15:53

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


            1. Arigotoma
              10.01.2024 15:53

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


      1. fasoGOda
        10.01.2024 15:53

        Ну, это да, речь просто про React, мне казалось, че там не сервере происходит мы не рассматриваем. В контексте реакта это не гонка


    1. steck
      10.01.2024 15:53
      +3

      В определении race condition нет ни слова про потоки.


      1. fasoGOda
        10.01.2024 15:53

        Открываем ссылку из статьи автора, и в первом же предложении там про многопоточность


    1. gravyzzap
      10.01.2024 15:53
      +1

      async/await позволяет организовать несколько логических потоков поверх одного физического, у которых может возникать гонка за общие ресурсы.

      Если сказать, что race condition это исключительно про физические потоки, то придётся придумать термин для описания гонки между логическими потоками, например logical race condition. Но пользы для народного хозяйства в этом отдельном термине не много.

      Можно пойти дальше, и сказать, что проблема вообще не в многопоточности, а в конкурентности.


  1. Nik1984z
    10.01.2024 15:53

    Извините, за, может быть, наивный вопрос: а что плохого в том чтобы "обмазать результат хука async/await"?))


    1. Olegas Автор
      10.01.2024 15:53
      +1

      А как нам это поможет? Вернем из хука Promise? Ну допустим, давай попробуем...

      const result = useFetch(url); // result - Promise

      Что дальше? Напишем await?

      const data = await result; 

      Допустим, но тогда внешняя функция должна быть async?

      async function MyComponent() {
        const result = useFetch(url);
        const data = await result;
        return <>{data}</>
      }

      Но в этом случае функция MyComponent возвращает что? Правильно, Promise. А можно из React-компонента вернуть Promise? Как это будет работать?


      1. Nik1984z
        10.01.2024 15:53

        Теперь ясно, спасибо. Я изначально подумал об оборачивании феча в async await и соответственно try catch)


  1. VanyaMate
    10.01.2024 15:53
    +3

    Здравствуйте)

    Мне кажется, что еще можно сделать такие улучшения.

    1. Изначально задать isLoading в true. Ну или сделать проверку, что если url есть, то true, иначе false, но это если мы допускаем, что url может быть пустым.
    В таком случае мы избавимся от одного лишнего ререндера когда isLoading, при первом вызове, будет становится в true. Но тогда еще и проверку внутри useEffect можно делать, чтобы не делать лишних действий если url не правильный/его в принципе не указали.

    2. Я делал еще так, что в цепочке промисов - я не сразу обновляю стейт, а сохраняю в переменные внутри useEffect, чтобы избежать лишних рендеров. А в конце в finally устанавливаю всё сразу. В конкретно этом примере, опять же, это не нужно, но в более сложных - может понадобиться. Например если мы каким-то асинхронным валидатором решим проверить наши данные о.О ну условно) Или банально делаем несколько последовательных запросов или асинхронных операций)

    function useFetch(url) {
       const [data, setData] = useState(null);
       const [isLoading, setIsLoading] = useState(true);
       const [error, setError] = useState(null);
    
       useEffect(() => {
          // флаг отмены
          let cancelled = false;
          let data = null;
          let error = null;
    
          setIsLoading(true);
          setData(null);
          setError(null);
          fetch(url)
             .then((res) => res.json())
             .then((respData) => {
                if (!cancelled) data = respData;
             })
             .catch((e) => {
                if (!cancelled) error = e;
             })
             .finally(() => {
                if (!cancelled) {
                  setData(data);
                  setError(error);
                  setIsLoading(false);
                }
             });
    
          return () => {
             // выставим признак того, что запрос отменен
             cancelled = true;
          };
       }, [url]);
    
       return [data, isLoading, error];
    }


    Это что касается именно реакта.

    Так же - конечно, лучше, как уже писали, и мне так тоже кажется, использовать AbortController.
    Так же - я бы использовал не массив для возвращения, а объект, чтобы брать только то что нужно.
    Так же - кеширование fetch, или, например, хранить кеши внутри хука.. если нужно.
    В общем от задачи хука много зависит) Думаю так.


    1. Olegas Автор
      10.01.2024 15:53
      +1

      По поводу объекта и минимизации перерисовок - это отличное замечание, спасибо!

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


      1. mi5ha6in
        10.01.2024 15:53

        Или просто использовать TanStack Query


      1. VanyaMate
        10.01.2024 15:53

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


    1. 8bitjoey
      10.01.2024 15:53

      Не надо использовать объект, это зло. С массивом вам тоже никто не запрещает брать только то, что нужно:

      const [myData] = useFetch(...);
      const [anotherData,, error] = useFetch(...);
      const [, loading] = useFetch(...);

      И массив избавляет от глупых переименований, когда используются несколько таких хуков. Если бы возвращали объект, то пример выше надо было бы переписать так:

      const { data: myData } = useFetch(...);
      const { data: anotherData, error } = useFetch(...);


      1. Olegas Автор
        10.01.2024 15:53

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


      1. z0rlog
        10.01.2024 15:53

        А можно поподробнее почему объект зло? Ну кроме переименований.


        1. 8bitjoey
          10.01.2024 15:53

          Собственно, этим. Неудобство использования с множественными хуками. Тот же useState не случайно возвращает массив, а не что-то вроде {state, setState}. Представьте, как выглядел бы код, будь оно так.

          В остальном, никто не мешает использовать объекты, особенно, если есть уверенность, что таковой хук будет использовать только единожды в компоненте. Например, значение возвращаемое useContext.


          1. Ekseft
            10.01.2024 15:53

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

            Объект же даёт вам подсказку в ИДЕ и избавляет от необходимости вешать запятые в воздухе.


            1. 8bitjoey
              10.01.2024 15:53

              Если у вас есть IDE, то она подскажет порядок и для массивов. Если вы используете TS, то там еще проще - можно указать название каждого элемента.

              Меня лично не напрягают висящие запятые, они не мешают чтению кода.

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


  1. DmitryKazakov8
    10.01.2024 15:53
    +4

    Эта задача проверяет исключительно понимание реализации на функциональных компонентах Реакта с использованием хуков. Для проверки этого можно придумать пример порелевантней, потому что если использовать кейс получения данных по апи - то адекватный ответ для всех, кроме джунов, это - "так делать нельзя". А джуны как раз будут пилить setState, useEffect, обрабатывать ошибки и бороться с race condition) То есть как раз "уверенно владеющие основами" люди. Если надо найти именно таких - то статья релевантная, хотя лучше бы без вызова апи, потому что отсекает более опытных разрабов.

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

    • как организовать апи, чтобы можно было вызывать как из Реакта, так и из экшенов / моделей / реакций, и при этом в Реакте можно было узнать состояние запроса и отобразить лоадер

    • как сделать изоморфные вызовы во всех этих кейсах, чтобы SSR дожидался выполнения всех вызовов из всех мест и показывал финальный html пользователю, при этом при ошибке критичных запросов редиректил на страницу 500 или применял другую стратегию

    • как организовать типизированные запросы (чтобы не строки передавать в качестве урла, а аргументы функции) и обогащение запросов хедерами типа авторизации (это тема про "отдельный независимый слой апи")

    • как тестировать апи с моками и отдельно от вью/моделей и других слоев, а также в связке с ними

    • как сделать реалтаймовую валидацию входящих-исходящих данных исходя из TS-моделей

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

    И т.п. То есть вопрос про вызов апи - это отдельная большая тема. А вопрос про хуки Реакта и асинхронщину внутри них - совсем другая. И если вопрос про апи, то там наиболее адекватно было бы сказать, что хуки для этого не подходят, нужно использовать классовые компоненты, что приведет к отдельной ветке разговора)


    1. Olegas Автор
      10.01.2024 15:53
      +1

      Со всем согласен, кроме "отсекания более опытных разрабов". Можно использовать задачу как отправную точку. Ответ "так нельзя" это отличный повод задать вопрос "а почему?" и продолжить разговор, выслушать все, что описано выше.


      1. DmitryKazakov8
        10.01.2024 15:53
        +2

        Да, как отправную точку - отлично, но в выводе статьи - "Задачка позволяет проверить, как кандидат понимает устройство рендеринга React...", то есть ответ "так нельзя" скорее всего приведет к тому, что интервьюер либо решит, что задачу кандидат не решил и не знает основ, либо не сможет проверить эти знания потому что под рукой нет более подходящей задачи. То есть все же считаю что правильно сказал - определенные разрабы отсекутся этой задачей, потому что она проверяет для интервьюера одно, а для соискателя может быть совсем другое (знание архитектур, а не setState и useEffect Реакта)

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


        1. Olegas Автор
          10.01.2024 15:53
          +1

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

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

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

          Еще возможна ситуация, когда на проекте все означенные вопросы уже решены и решать их как-то иначе - не требуется. Возможно нам тут действительно не нужен архитектор, а нужен твердый мидл с хорошим пониманием базы? При собеседовании надо все же понимать, кого мы хотим нанять и зачем. И таки да, мы можем срезать тут overqualified людей. Но возможно это именно то, что в данной ситуации было нужно?

          И такие найдутся, которые будут считать что это задача на хуки, а кандидат думать что на апи - и разойдутся.

          Так на то оно и собеседование, что бы люди друг с другом поговорили. Потому что разработка современных продуктов это про команду, общение, аргументацию и договоренности.

          Хороший кандидат задаст вопрос - что хотим тут получить? Уточнит требования, задаст вопросы о валидации, изоморфности и т.п. если это позволяет его кругозор. Хороший интервьюер направит в нужное русло и не будет слепо следовать "скрипту", сравнивать решение кандидата построчно с кодом из статьи на Хабре, верно же? )


          1. DmitryKazakov8
            10.01.2024 15:53
            +1

            Все так, для статьи "любимая задача про знание Реакт" придраться больше и не к чему, кроме как к тому, что интервьюеры "могут не обладать соответствующими знаниями". Но вот к "Вот такой вариант я считаю "идеальным"" придраться можно очень много к чему) потому что код в статье - это решение джуна, неприменимое к реальности


            1. Olegas Автор
              10.01.2024 15:53

              А что не так с кодом? А что в нем поменяет с ростом уровня "сеньйорности" собеседуемого? Уточню - это не тестовое задание "на дом". Это задачка "на вайтборде", здесь и сейчас, минут на 10-15, не больше.

              Ее основная цель (повторю в который раз) - проверить понимание основ React.

              Конечно же она НЕ используется как единственный критерий оценки.


  1. fancy-apps
    10.01.2024 15:53
    +1

    Для собеседования хорошая задачка, но последним вопросом должно быть - почему этот хук это плохо и что должно быть вместо него


    1. kioley
      10.01.2024 15:53
      +2

      А что должно быть?


      1. Olegas Автор
        10.01.2024 15:53

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


  1. Modin
    10.01.2024 15:53
    +1

    Этот хук не будет работать как ожидается без проверки статуса ответа


  1. EGO7000
    10.01.2024 15:53
    +1

    У меня 2 вопроса/замечания:

    1. Вы с помощью таких задач ищете людей с опытом, чтобы они и в проде такое выдавали и считали это нормой?

    2. Вы уверены, что правильно понимаете понятие race condition? Это не риторический вопрос, т.к. если мы запросили 2 разных url через этот хук, то это не состояние гонки. Гонка это когда у вас 2 одинаковых запроса идут и кто первый ответил, тот и молодец))) А у вас по коду получается, что компонент при монтировании/размонтировании просто для вида локальную переменную поменяет и тут же вычистит. Запрос при этом может уйти на сервер, исполнится там с 200 OK и, например, в случае с JWT, обновит токен с ответом вникуда, что повлечёт следом некорректную работу на фронте (невалидный токен).


    1. Olegas Автор
      10.01.2024 15:53

      1. Вы с помощью таких задач ищете людей с опытом, чтобы они и в проде такое выдавали и считали это нормой?

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

      Вы уверены, что правильно понимаете понятие race condition?

      Уверен. Более чем. Это именно состояние гонки. Т.к. без обработки "отмены" тайминг обработки запроса сервером и его RTT будет влиять на результат, который получит пользователь. В том числе мы можем получить что "молодец" как раз не тот, кто ожидался.

      А у вас по коду получается, что компонент при монтировании/размонтировании просто для вида локальную переменную поменяет и тут же вычистит

      Не забывайте про смену зависимостей эффекта. Переменная доступна через замыкание внутри колбэков промиса загрузки и внутри функции очистки эффекта.

      Запрос при этом может уйти на сервер, исполнится там с 200 OK и, например, в случае с JWT, обновит токен с ответом вникуда, что повлечёт следом некорректную работу на фронте (невалидный токен).

      Может, если на проекте авторизация по JWT. Но в условиях задачи нет ограничений и сказано что нужно просто загрузить данные по URL. Кандидат безусловно может сделать такое предположение и сообщить об этом, что будет безусловно в плюс. В этой точке я скажу что "забудь об этом, это ручка без авторизации, просто загрузи содержимое" и мы пойдем дальше.


  1. WildeDJ
    10.01.2024 15:53

    Почему именно задача про загрузку данных? Рассматривали ли вы задачи связанные с context и его особенности ре-рендера? Сколько не посещал таких мероприятий почти всегда было "напишите ка нам хук, где нужно данные получить"


    1. Olegas Автор
      10.01.2024 15:53

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


  1. EvgenichTalagaev
    10.01.2024 15:53
    +1

    Спасибо, было интересно.