Вопрос по redux, reactjs, redux-thunk, asynchronous – Redux: использование асинхронного промежуточного программного обеспечения и диспетчеризация действий для функций успеха

4

Я пытаюсь интегрировать Redux в свой проект React. В настоящее время я не использую фреймворк Flux.

Мое приложение получает некоторые данные из API и отображает их довольно красиво, например так:

componentDidMount() {
  getData();
}

getData() {
  const self = this;

  ajax({
    url: apiUrl,
  })
  .success(function(data) {
    self.setState({
      data: data,
    });
  })
  .error(function() {
    throw new Error('Server response failed.');
  });
}

Читая о Redux, я остановился на двух возможных подходах, которые я мог бы использовать для хранения своих данных об успехах в магазине:

Используйте асинхронное промежуточное ПО илиДиспетчерское действиеADD_DATA из обратного вызова успеха функции AJAX

Но я не уверен, какой подход лучше.

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

Ваш Ответ

4   ответа
2

Ни один из подходов не лучше, потому что они одинаковы. Независимо от того, отправляете ли вы действия в обратных вызовах или используете избыточные thunks, вы эффективно делаете следующее:

  // do some async thing
  // when async thing is done, dispatch an action.
}

Лично я предпочитаю пропускать промежуточное ПО / thunks и просто использовать обратные вызовы. Я не думаю, что дополнительные издержки, связанные с промежуточным программным обеспечением / thunks, необходимы, и на самом деле не так сложно написать свою собственную функцию «async action creator»:

var store = require('./path-to-redux-store');
var actions = require('./path-to-redux-action-creators');

function asyncAction(options) {
  $.ajax({
    url: options.url,
    method: options.method,
    success: function(response) {
      store.dispatch(options.action(response));
    }
  });
};

// Create an async action
asyncAction({
  url: '/some-route',
  method: 'GET',
  action: actions.updateData
}); 
1

что вы действительно спрашиваете, должен ли ваш AJAX-вызов быть вашим создателем действий или вашим компонентом.

Если ваше приложение достаточно маленькое, хорошо, чтобы оно было в вашем компоненте. Но по мере того, как ваше приложение становится больше, вы захотите провести рефакторинг. В более крупном приложении вы хотите, чтобы ваши компоненты были максимально простыми и предсказуемыми. Наличие вызова AJAX внутри вашего компонента значительно увеличивает его сложность. Более того, наличие вызова AJAX внутри создателя действия делает его более пригодным для повторного использования.

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

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

Следующее взято непосредственно изredux-thunk страница github:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';

// create a store that has redux-thunk middleware enabled
const createStoreWithMiddleware = applyMiddleware(
    thunk
)(createStore);

const store = createStoreWithMiddleware(rootReducer);

Вот и все. Теперь у вас могут быть создатели асинхронных действий.

Ваш будет выглядеть так:

function getData() {

    const apiUrl = '/fetch-data';

    return (dispatch, getState) => {

        dispatch({
            type: 'DATA_FETCH_LOADING'
        });

        ajax({
            url: apiUrl,
        }).done((data) => {
            dispatch({
                type: 'DATA_FETCH_SUCCESS',
                data: data
            });
        }).fail(() => {
            dispatch({
                type: 'DATA_FETCH_FAIL'
            });
        });

   };

}

Вот и все. Всякий раз, когда создатель действия возвращает функцию, промежуточное ПО Thunk предоставляетdispatch (а такжеgetState который вам может не понадобиться) для разрешения асинхронных действий.

10

достижения этой цели. Это делает действия немного легче следовать и имеет меньше стандартного IMO.

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

Например, я использую действие, которое выглядит так:

export function fetchData() {
  return {
    types: [ FETCH_DATA, FETCH_DATA_SUCCESS, FETCH_DATA_FAILURE ],
    promise: api => api('foo/bar')
  }
}

Моя пользовательская промежуточная программа видит, что объект имеетtypes массив иpromise функция и обрабатывает это специально. Вот как это выглядит:

import 'whatwg-fetch';

function isRequest({ promise }) {
  return promise && typeof promise === 'function';
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  } else {
    const error = new Error(response.statusText || response.status);
    error.response = response.json();
    throw error;
  }
}

function parseJSON(response) {
  return response.json();
}

function makeRequest(urlBase, { promise, types, ...rest }, next) {
  const [ REQUEST, SUCCESS, FAILURE ] = types;

  // Dispatch your request action so UI can showing loading indicator
  next({ ...rest, type: REQUEST });

  const api = (url, params = {}) => {
    // fetch by default doesn't include the same-origin header.  Add this by default.
    params.credentials = 'same-origin';
    params.method = params.method || 'get';
    params.headers = params.headers || {};
    params.headers['Content-Type'] = 'application/json';
    params.headers['Access-Control-Allow-Origin'] = '*';

    return fetch(urlBase + url, params)
      .then(checkStatus)
      .then(parseJSON)
      .then(data => {
        // Dispatch your success action
        next({ ...rest, payload: data, type: SUCCESS });
      })
      .catch(error => {
        // Dispatch your failure action
        next({ ...rest, error, type: FAILURE });
      });
  };

  // Because I'm using promise as a function, I create my own simple wrapper
  // around whatwg-fetch. Note in the action example above, I supply the url
  // and optionally the params and feed them directly into fetch.

  // The other benefit for this approach is that in my action above, I can do 
  // var result = action.promise(api => api('foo/bar'))
  // result.then(() => { /* something happened */ })
  // This allows me to be notified in my action when a result comes back.
  return promise(api);
}

// When setting up my apiMiddleware, I pass a base url for the service I am
// using. Then my actions can just pass the route and I append it to the path
export default function apiMiddleware(urlBase) {
  return function() {
    return next => action => isRequest(action) ? makeRequest(urlBase, action, next) : next(action);
  };
}

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

Если бы я хотел использовать Redux-Thunk с промежуточным программным обеспечением .. Могу ли я сделать это @ nross83? Мне нужно отправить вызов для API, и в случае успеха еще несколько отправок Harkirat Saluja
Я использую аналогичный подход в моем приложении. Это также отличный подход, если вы хотите, чтобы центральное место отправляло действие в ответ на события, связанные с API. Например. Отображение / скрытие загрузчиков, перенаправление пользователя на экран входа в случае ответа 401. Без этого отправка таких действий была бы засорена по всей вашей кодовой базе, где бы вы ни делали вызовы API. Исходя из Angular, это помогает мне реализовать функциональность, которую достигли перехватчики. akaashanky
@HarkiratSaluja Да, просто добавьте промежуточное программное обеспечение Thunk (вместе с вашим пользовательским промежуточным программным обеспечением), и оно будет работать нормально. Вы можете использовать функцию applyMiddleware от Redux и передать все промежуточные программы, которые вы хотели бы использовать. Я использую Thunk, а также пользовательское промежуточное ПО в своем собственном проекте.redux.js.org/docs/api/applyMiddleware.html nross83
3

я используюredux-thunk сделать вызов AJAX иredux-promise выполнить обещание, как показано ниже.

  function getData() {             // This is the thunk creator
    return function (dispatch) {   // thunk function
      dispatch(requestData());     // first set the state to 'requesting'
      return dispatch(
        receiveData(               // action creator that receives promise
          webapi.getData()         // makes ajax call and return promise
        )
      );
    };
  }

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

thunks позволяют отправлять несколько действий (как в приведенном выше примере - сначала установить состояние «запрашивающий», которое можно использовать при загрузке индикаторов и т. д.)это позволяет условно рассылать дополнительные действия. Например, выборка, только если время с момента последней выборки превышает порогвы все еще можете реализовать все это без промежуточного программного обеспечения, но использование промежуточного программного обеспечения поможет вам сохранить все асинхронные поведения в создателях действий
Да, я знаю. Но есть ли что-то хорошее в этом методе, чем простой обратный вызов ajax? Ateev Chopra

Похожие вопросы