Зачем нужен redux-thunk?

Сегодня с коллегой возникла небольшая дискуссия, я утверждал, что redux-thunk очень удобная надстройка (middleware) над redux и позволяет создавать асинхронные экшены.
Коллега возразил, зачем нужен redux-thunk, когда можно сделать вот так:
export function load(){
    setTimeout(()=>{
        store.dispatch(getProfileSuccess({id: 1}));
    }, 3000)
}

Т.е он импортит store в определенный файл проекта и вызывает несколько экшенов

По началу я впал в ступор, действительно, зачем redux-thunk, если можно испортить стор, но позже проанализировав ситуацию, пришел к выводу, что асинхронные экшены, например как в примере выше загрузка профиля должна иметь 3 состояния:
- старт загрузки профиля (для отображения лоадера)
- данные профиля успешно загружены
- возникла ошибка при загрузке данных
исходя из этого, если действовать по методу коллеги, необходимо создавать для каждого действия отдельную функцию (экшены)

Вот пример с использованием redux-thunk
export function getProfile () => {
  return dispatch => {
    // диспатчим лоадер
    dispatch({
      type: GET_PROFILE_START,
      payload: true
    })
    
    axios.get('/user')
      .then(res => {
        // успешно получили данные
        dispatch({
          type: GET_PROFILE_SECCUESS
          payload: res.data
        })
      })
      .cath(err => {
        // Ошибка...
        dispatch({
          type: GET_PROFILE_ERROR
          payload: true
        })
      })
  }
}


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

Что вы скажите, какое мнение верно, и имеет ли права на жизнь предложенное коллегой решение?
  • Вопрос задан
  • 16823 просмотра
Решения вопроса 2
maxfarseer
@maxfarseer
https://maxpfrontend.ru, обучаю реакту и компании
Если я правильно понял вашего коллегу, то речь была не о том, что нужно асинхронные функции через setTimeout вызывать, а это был просто пример, как сделать какой-то кусочек "типа асинхронным".
Его довод был в том, что вместо вызова dispatch из замыкания (полученного с помощью redux-thunk, например) он вызывал store.dispatch напрямую (то есть у объекта store, и этот store импортировал бы в каждом файле).

В таком случае, у redux-thunk - одно преимущество явное - не нужно импортировать store в каждом файле.

В остальном, все очень четко расписано в ответе Дэна Абрамова, который привел holymotion.
Если быть кратким, то вам нужна функция dispatch, ведь именно через нее вы "диспатчите" свои экшены. Вы не можете в асинхронном ответе написать:
...
axios.get('/user')
      .then(res => {
        // успешно получили данные
        dispatch({ // <-- здесь вы вызываете функцию dispatch, а если она к вам не пришла в анонимной функции, с помощью redux-thunk, то октуда вы ее возьмете?
          type: GET_PROFILE_SECCUESS
          payload: res.data
        })
      })
...


Поэтому вы были бы обязаны в каждый action creator, который является асинхронным, передавать бы помимо нужных вам аргументов, еще и функцию dispatch из своего контейнера. Что не удобно. (это все есть по ссылке на stackoverflow, но более подробно)
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
devellopah
@devellopah
Я бы сказал, что redux-thunk, redux-saga или какое-то другое "решение" для организации сайд-эффектов не является необходимой зависимостью для любого приложения, написанного на reactjs.
Точно так же как и не является необходимостью сам redux. Но если ваше приложение нуждается в инструменте для управления состоянием(redux), то автоматически из этого следует, что оно так же нуждается в инструменте для организации сайд-эффектов.

В redux-thunk вы диспатчите функцию словно это action. Это очень важно. В контейнере вне зависимости от "природы" экшена, вы будете писать this.props.dispatch(whateverAction).

А ваш коллега, напротив, будет вынужден синхронные экшены диспатчить через this.props.dispatch(syncAction), а асинхронный просто вызовом функции, содержащей setTimeout.

Как-то не очень красиво, да и самому контейнеру не обязательно знать какие экшены синхронные, а какие асинхронные.
Ответ написан
@Hydrock
Тоже страдаю от этого вопроса. Лично мне, наоборот, не нравится что логика выносится в экшен креэйторы. Саги как то больше подходят.
Ответ написан
xakplant
@xakplant
Автор сайта xakplant.ru
Действительно, скорее всего это про организацию кода.
Если мы делаем наше react-приложение возможно, что однажды нам придётся изменить хранилище. Вообще дурной тон использовать dispatch в самом компоненте не обернув его в HOC. Ведь это сразу делает невозможным переиспользование. Например у нас есть компонент, который рендерит какой-то список и использует redux. Для того, чтобы мы могли его переиспользовать правильно сделать так:

import React, { Component } import 'react';
import List from './List'; // Список
import { connect } from 'react-redux'
import { mutatinList } from './actions'; // Какой-то action

class ListContainer extends Component{
	render(){
		return(
			<List {...this.props} />
		)
	}
}

const mapStateToProps = (state) => ({
    list: state.list
})

const mapDispatchToProps = {
	mutatinList: mutatinList
}

export default connect(mapStateToProps, mapDispatchToProps)(ListContainer);


Если мы захотим переиспользовать наш спискок то нам не придётся переписывать сам компонент, а можем лишь написать новый HOC

Ещё по этой теме я написал небольшую статью
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы