Каков наилучший подход к написанию избыточных действий, которые требуют данных от других действий - PullRequest
0 голосов
/ 10 апреля 2019

Я провел некоторое исследование о возможных способах сделать это, но я не могу найти тот, который использует ту же архитектуру, что и в приложении, над которым я работаю. Например, React docs говорят, что у нас должен быть метод, который делает HTTP-запрос и затем вызывает действия в разных точках (когда запрос начинается, когда ответ получен и т. Д.). Но у нас есть другой подход. Мы используем действие, которое выполняет HTTP-вызов, а затем отправляет результат. Чтобы быть более точным, мой вариант использования таков:

// action to get resource A
getResourceA () {
  return dispatch => {
    const result = await axios.get('someLink');
    dispatch({
      type: GET_RES_A,
      payload: result
    });
  }; 
}

// another action which needs data from resource A
getSomethingElseByIdFromA (aId) {
  return async dispatch => {
    const result = await axiosClient.get(`someLink/${aId}`);
    dispatch({
      type: GET_SOMETHING_BY_ID_FROM_A,
      payload: result
    });
  }; 
}

Как уже говорилось, для второго действия нужны данные из первого.

Теперь я знаю два способа сделать это:

  1. вернуть результат первого действия
getResourceA () {
  return async dispatch => {
    const result = await axios.get('someLink');
    dispatch({
      type: GET_RES_A,
      payload: result
    });
    return result;
  }; 
}

// and then, when using it, inside a container
async foo () {
  const {
    // these two props are mapped to the getResourceA and
    // getSomethingElseByIdFromA actions
    dispatchGetResourceA,
    dispatchGetSomethingElseByIdFromA
  } = this.props;

  const aRes = await dispatchGetResourceA();
  // now aRes contains the resource from the server, but it has not
  // passed through the redux store yet. It's raw data
  dispatchGetSomethingElseByIdFromA(aRes.id);
}

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

  1. создайте "агрегатную" службу и используйте метод getState для доступа к состоянию после завершения действия.
aggregateAction () {
  return await (dispatch, getState) => {
    await dispatch(getResourceA());
    const { aRes } = getState();
    dispatch(getSomethingElseByIdFromA(aRes.id));
  };
}

А потом просто вызовите это действие в контейнере.

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

Ответы [ 2 ]

1 голос
/ 10 апреля 2019

Я думаю, что использование / использование Epic из redux-observable будет наиболее подходящим для вашего случая использования.Это позволило бы действиям пройти сначала по всем вашим редукторам (в отличие от упомянутого выше подхода), прежде чем обрабатывать их в той же логике.Кроме того, использование потока действий позволит вам манипулировать данными во всем их потоке, и вам не придется хранить ненужные вещи.Реактивное программирование и сам наблюдаемый шаблон имеют некоторые большие преимущества, когда речь заходит об асинхронных операциях, что является лучшим вариантом, чем redux-thunk, sagas и т. Д. Imo.

0 голосов
/ 10 апреля 2019

Я бы взглянул на использование пользовательского промежуточного программного обеспечения (https://redux.js.org/advanced/middleware). Использование промежуточного программного обеспечения может облегчить достижение такого рода вещей.

Что-то вроде:

 import {GET_RESOURCE_A, GET_RESOURCE_B, GET_RESOURCE_A_SUCCESS, GET_RESOURCE_A_ERROR  } from '../actions/actionTypes'

    const actionTypes = [GET_RESOURCE_A, GET_RESOURCE_B, GET_RESOURCE_A_SUCCESS, GET_RESOURCE_A_ERROR ]

    export default ({dispatch, getState}) => {

        return next => action => {

            if (!action.type || !actionTypes.includes(action.type)) {

                return next(action)

            }

            if(action.type === GET_RESOURCE_A){
              try{
                // here you can getState() to look at current state object 
                // dispatch multiple actions like GET_RESOURCE_B and/ or 
                // GET_RESOURCE_A_SUCCESS
                // make other api calls etc....
               // you don't have to keep stuff in global state you don't 
               //want to you could have a varaiable here to do it
              }
             catch (e){

              }  dispatch({type:GET_RESOURCE_A_ERROR , payload: 'error'})
            }

        }

    }
...