У меня есть следующий шаблон, который я использую, чтобы указать, когда вызов API начался, успешно или сбой:
import actionCreatorFactory from "typescript-fsa";
import { reducerWithInitialState } from "typescript-fsa-reducers";
export interface IAPIOperation<TFailurePayload> {
pending: boolean;
success: boolean;
failure: boolean;
error: TFailurePayload;
}
const CreateAPIOperationReducer = <
TStartPayload,
TSuccessPayload,
TFailurePayload
>(
opName: string,
failurePayloadInitialState: TFailurePayload
) => {
const initialState: IAPIOperation<TFailurePayload> = {
pending: false,
success: false,
failure: false,
error: failurePayloadInitialState
};
const actionCreator = actionCreatorFactory();
const actions = {
...actionCreator.async<TStartPayload, TSuccessPayload, TFailurePayload>(
opName
)
};
const reducer = reducerWithInitialState(initialState)
.case(actions.started, (state, _PAYLOAD) => {
return Object.assign({}, state, initialState, {
pending: true
});
})
.case(actions.done, (state, _PAYLOAD) => {
return Object.assign({}, state, initialState, {
success: true
});
})
.case(actions.failed, (state, payload) => {
return Object.assign({}, state, initialState, {
failure: true,
error: payload
});
});
return {
reducer,
actions: {
started: actions.started,
done: actions.done,
failed: actions.failed,
},
initialState
};
};
export default CreateAPIOperationReducer;
Внутри моего фактического редуктора я использую CreateAPIOperationReducer
и комбинирую его с моим фактическим редуктором, чтобы я мог отслеживать вызов API, связанный с состоянием редуктора:
import { combineReducers } from "redux";
import { reducerWithInitialState } from "typescript-fsa-reducers";
import createAPIOperationReducer, { IAPIOperation } from "./APIOperation";
export interface IRegistration {
registrationUrl: string;
}
const initialRegState: IRegistration = {
registrationUrl: ""
};
export interface IRegistrationState {
registration: IRegistration;
registrationAPIOperation: IAPIOperation<string>;
}
export const registerAPIOperation = createAPIOperationReducer<
string,
string,
string
>("REGISTER", "");
export const actions = {
registerAPIOperationActions: {
...registerAPIOperation.actions
}
};
export const initialState: IRegistrationState = {
registration: initialRegState,
registrationAPIOperation: registerAPIOperation.initialState
};
const registration = reducerWithInitialState(initialRegState).case(
actions.registerAPIOperationActions.done,
(state, payload) => {
return Object.assign({}, state, {
registrationUrl: payload.result
});
}
);
export default combineReducers<IRegistrationState>({
registration,
registrationAPIOperation: registerAPIOperation.reducer
});
На одной из моих страниц-контейнеров (назовем это RegPage
) я отправляю действие started
, равное registrationAPIOperation
, и в моем наблюдаемом редуксе эпосе я обрабатываю это действие, выполняя вызов API, а затем, наконец, Я отправляю действие done
из эпоса, которое устанавливает флаг success
в true на редукторе операций API.
В RegPage
Я проверяю, установлено ли registrationAPIOperation.success
на true
при обновлении реквизита, и если это так, я перенаправляю с этой страницы на другую.
Теперь одна из проблем, с которыми я сталкиваюсь, заключается в том, что если я захочу вернуться к RegPage
, он обнаружит, что registrationAPIOperation.success
по-прежнему верен, и немедленно перенаправит снова.
Один из способов решить эту проблему - добавить к CreateAPIOperationReducer
действиям следующее:
reset: actionCreator(`${opName}/RESET`)
И обработайте это в CreateAPIOperationReducer
как таковое:
case(actions.reset, state => {
return Object.assign({}, state, initialState);
})
Затем я могу позвонить reset
, прежде чем перенаправить с RegPage
, что означает, что если я вернусь к RegPage
, он не будет перенаправлять.
Это хороший шаблон для подражания? Есть ли лучший способ добиться того же, где мне нужно отслеживать состояние операций API и возвращать его к исходному, как только все будет сделано?
Сложность для меня при таком подходе заключается в том, что я чувствую, как только у меня появилось несколько редукторов операций API, мне нужно будет убедиться, что к ним вызывается reset
всякий раз, когда выполняется операция API (будь то успех или неудача). Не станет ли это источником потенциальных ошибок, если кто-то забудет позвонить reset
в нужное время или вообще? Я чувствую, что для этого может быть более общий подход, но я не могу думать об этом.