Какие плюсы и минусы Thunk-Based Development

Ответ

Плюсы:

  1. Простота внедрения — не требует сложных абстракций
  2. Хорошо подходит для простых асинхронных операций (запросы API)
  3. Понятный поток данных — действия диспатчатся последовательно
  4. Минимальный boilerplate по сравнению с Saga

Минусы:

  1. Сложность тестирования из-за side effects
  2. Проблемы с композицией асинхронных операций
  3. Callback hell при сложных цепочках действий
  4. Нет контроля над отменой операций
// Пример thunk
const fetchUser = (id) => async (dispatch) => {
  dispatch({ type: 'FETCH_USER_START' });
  try {
    const user = await api.getUser(id);
    dispatch({ type: 'FETCH_USER_SUCCESS', payload: user });
  } catch (error) {
    dispatch({ type: 'FETCH_USER_ERROR', payload: error });
  }
};

Ответ 18+ 🔞

Да ты посмотри, какая хуйня творится с этими thunk'ами! Ну, в рот меня чих-пых, как же их все нахваливают.

Что там у них хорошего, а?

  1. Впихнуть — не выпихнуть. Серьёзно, проще некуда. Никаких тебе ёбаных генераторов, yield и прочей саги — взял и написал функцию, которая возвращает другую функцию. И всё, пиздец, ты уже асинхронный гений.
  2. Для простых дел — огонь. Надо данные с сервака подёргать? Пожалуйста, один fetch, dispatch до, dispatch после — и в ус не дуешь.
  3. Видно, кто за кем. Действия летят одно за другим, как по маслу. Начало запроса, успех, ошибка — всё на виду, не запутаешься.
  4. Писанины меньше, чем в той же Saga. Не надо импортировать кучу эффектов, описывать сагу, форкать, вот это всё. Написал колбэк — и свободен.

А теперь, сука, ложка дёгтя, которая блядь целый чан!

  1. Тестировать — пиздец. Как, блядь, протестировать side effects, которые у тебя прямо в теле функции? Это ж надо мокать весь мир: и dispatch, и getState, и API-шку. Овердохуища мороки.
  2. Сложную логику не соберёшь. Ну-ка, попробуй организовать несколько параллельных запросов, которые потом ждут друг друга, или, хуле там, отмену предыдущего. Получится такая вложенная хуйня, что сам через неделю не разберёшь.
  3. Callback hell, ёпта! Запрос Б зависит от результата А, а потом ещё С нужно сделать... И вот ты уже пишешь then внутри then, или async/await на три этажа вглубь. Красота, блядь, смотреть противно.
  4. Отменить? Хуй там! Пользователь ушёл со страницы, а твой thunk уже пошёл делать запрос на десять гигов. Ну и пусть себе грузит, нахуй, память жрёт и трафик. Контроля-то никакого.
// Смотри, как это выглядит на практике. Просто, да?
const fetchUser = (id) => async (dispatch) => {
  dispatch({ type: 'FETCH_USER_START' }); // Диспатчим старт
  try {
    const user = await api.getUser(id); // Ждём, пока сервер не ответит
    dispatch({ type: 'FETCH_USER_SUCCESS', payload: user }); // Ура, диспатчим успех
  } catch (error) {
    dispatch({ type: 'FETCH_USER_ERROR', payload: error }); // Обосрались — диспатчим ошибку
  }
};

Короче, инструмент как инструмент. Для быстрого наброса и простых вещей — терпимо. Но как только логика начинает напоминать сценарий фильма про шпионов — всё, пидары, это не ваш выбор. Тут уже надо Saga или RTK Query смотреть, а то совсем охуеете.