Как получить результат от действия в другом действии?

Я новичок в dvajs. Я использую React 17,x, Typescript 4.2.3, antd 4.15.0, umi 3.4.7

Проблема. Если я перейду к /s/page, код должен получить некоторые категории из API и сделать еще один запрос к серверу, отображая их на некоторых страницах в это время. Но в момент вызова эффекта поиска категории пусты, поэтому я пытаюсь снова вызвать действие getCategories. Но категории по-прежнему пусты. Как получить результат от действия в другом действии? Может есть какая-то цепочка рассылки?

Код приведен ниже

      import { fetchCategories, makeSearch } from '@/services/search';
import { CategoriesModelStateSelector, Subscription } from '@@/plugin-dva/connect';
import { Reducer, Effect } from 'umi';
export type SearchModelState = {
  searchResults: Provider[]
  categories: Category[]
}
export type SearchModelType = {
  namespace: string;
  state: SearchModelState;
  effects: {
    getCategories: Effect;
    search: Effect;
  };
  reducers: {
    setCategories: Reducer
    setSearchResults: Reducer
  };
  subscriptions: {
    setup: Subscription
  }
};
export type SearchModelStateSelector = {
  search: SearchModelState
};
const SearchModel: SearchModelType = {
  namespace: 'search',
  state: {
categories: [],
searchResults: [],
},      
effects: {
    * getCategories({ payload }, { call, put, select }) {
      const response = yield call(fetchCategories);
  if (response) {
    yield put({
      type: 'setCategories',
      payload: response,
    });
  }
},
* search({ payload }, { call, put, select }) {
  let categories = yield select(({ categories: state }: CategoriesModelStateSelector) => state.categories);
  // HERE categories are empty
  console.log(categories);
  yield put({
    type: 'getCategories',
    payload: {},
  });

  let catss = yield select(({ categories: state }: CategoriesModelStateSelector) => state.categories);
  console.log(catss);
  // HERE categories are still empty

  const response = yield call(makeSearch, payload);
  yield put({
    type: 'setSearchResults',
    payload: response,
  });
},
},


    reducers: {
        setCategories(state, { payload }) {
          return {
            ...state,
            categories: response,
      };
    },
    setSearchResults(state, { payload }) {
      return {
        ...state,
        searchResults: response,
      };
    },
  },
  subscriptions: {
    setup({ dispatch, history }) {
      // @ts-ignore
      return history.listen(({ pathname, query }) => {
        dispatch({ type: 'getCategories', payload: {} });

        if (pathname === '/s' || pathname === '/s/') {
          dispatch({ type: 'search', payload: query });
        }
      });
    },
  },
};

export default SearchModel;

1 ответ

Решение

Предложенное решение:

      yield put({
    type: 'getCategories',
    payload: {},
  });

// something like this will wait until CATEGORIES_WERE_FETCHED was dispatched on 
// the store, before continuing to next line: 'take' is what you are looking for
yield take("CATEGORIES_WERE_FETCHED")

let catss = yield select(

Redux-Saga Take: создает описание эффекта, которое указывает промежуточному программному обеспечению ждать указанного действия в Магазине. Генератор приостанавливается до тех пор, пока не будет отправлено действие, соответствующее шаблону.

https://redux-saga.js.org/docs/api/

Я еще раз взглянул на ваш код:

      yield put({
      type: 'setCategories',
      payload: response,
    });

Вы используете действие «setCategories», поэтому вы можете использовать take («setCategories») - если вы хотите «подождать», пока какое-либо действие не будет отправлено, как описано выше.

Другие вопросы по тегам