Я хотел бы отслеживать запросы API, которые я делаю с помощью react-redux. Для этого я хотел бы сгенерировать идентификатор запроса внутри действия и передать его промежуточному программному обеспечению и редукторам через полезную нагрузку. Затем, когда я отправляю действие из своего компонента, я могу захватить идентификатор запроса и использовать его для обновления компонента по мере выполнения запроса.
Вот пример кода
Состояние
export interface State {
[requestId: number]: Request;
}
export interface Request {
status: string;
error?: string;
}
Действие
export function createRequest(): Action {
return {
type: "request",
payload: {
requestId: Math.random () // Make a random Id here
}
};
}
Редуктор
export function createRequestReducer(state: State): State {
return {
...state,
...{ state.payload.requestId: { status: "pending" } }
};
}
Составная часть
interface props {
getRequestById: (id: number) => Request;
createRequest: () => number;
}
const component = (props: testProps): JSX.Element => {
const getRequestById = props.getRequestById;
const [requestId, setRequestId] = useState(null);
const [request, setRequest] = useState(null);
useEffect(() => {
if (requestId !== null) {
setRequest(getRequestById(requestId));
}
}, [requestId]);
return <div>The request status is {(request && request.status) || "Not started"}</div>;
}
function mapStateToProps(state: State) {
return {
getRequestById: (requestId: number): Request => {
getRequestById(state, requestId)
}
};
}
function mapDispatchToProps(dispatch: Dispatch) {
return {
createRequest: (): number => {
const action = createRequest();
dispatch(action);
return action.payload.requestId;
}
};
}
export default connect(mapStateToProps, mapDispatchToProps)(component);
Я ожидаю, что это сработает, но это может быть массовый анти-паттерн. Разве это не рекомендуется, и если да, то есть ли альтернатива?
Я думаю, что ваш подход работает технически совершенно нормально. Только "логически" возможно есть смысл внести некоторые изменения:
Да, «экшн» — это то, что должно быть отправлено редюсеру (и больше нигде не использовано, хотя технически с этим проблем нет).
Но что вы можете сделать:
Внутри функции создания действий вы можете делать все, что захотите.
Таким образом, вы можете создавать и использовать action
и requestId
отдельно.
Технически это то же самое, что и вы, но логически разделенное.
Например.:
function createRequest(){
const requestId = createUniqueId();
const action = { type: "request", payload: { requestId: requestId } };
return {
requestId: requestId, // <-- request id independent of the action
action: action, // <-- action independent of the request id
};
}
function mapDispatchToProps( dispatch: Dispatch ){
return {
createRequest: (): number => {
const { requestId, action } = createRequest();
dispatch( action ); // <-- action independent of the request id
return requestId; // <-- request id independent of the action
}
};
}
Мне (и, видимо, другим) нравится использовать то, что я называю «диспетчерами действий». Это лишний шаг и больше кода, но я думаю, что когда вы привыкнете к этой концепции, она устранит любые сомнения, где нужно размещать такой код.
Например.:
// Create the action, and nothing else:
const createRequestActionCreator = function( requestId ){
return { type: "request", payload: { requestId: requestId } };
};
// Preper some data needed to create the action:
const createRequestActionDispatcher = function( dispatch ){
return function(){
const requestId = createUniqueId();
dispatch( createRequestActionCreator( requestId ) );
return requestId;
};
};
//
function mapDispatchToProps( dispatch: Dispatch ) {
return {
createRequest: (): number => {
const requestId = createRequestActionDispatcher( dispatch )();
return requestId;
}
};
}
Кроме того, вы можете передать такой «диспетчер действий» непосредственно в качестве реквизита, если хотите.
В этом случае он в основном заменяет вашу функцию в mapDispatchToProps
, но может использоваться повторно, например:
function mapDispatchToProps( dispatch: Dispatch ) {
return {
createRequest: createRequestActionDispatcher( dispatch ),
};
}
Некоторые люди предпочитают использовать здесь функцию жирной стрелки, которую я нахожу более не менее запутанной, но она выглядит чище, как только вы привыкнете к этому шаблону:
const createRequestActionDispatcher = (dispatch: Dispatch) => (maybeSomeValue: MyType) => {
const requestId = createUniqueId();
dispatch( createRequestActionCreator( requestId ) );
return requestId;
};
Обычно я предпочитаю быть последовательным, для чего я должен всегда (или никогда) использовать эти «диспетчеры действий»,
но я обнаружил, что большую часть времени они мне не нужны, но иногда я нахожу их очень полезными.
Так что я на самом деле использую dispatch( myAction )
в некоторых местах и myActionDispatcher(value)(dispatch)
в других.
Мне это не нравится, но это работает хорошо, и у меня нет лучшей идеи.
Спасибо, мне нравится идея иметь диспетчеров для этого материала. Это кажется самым простым способом хранения идентификаторов запросов без хранения множества метаданных о запросе для их идентификации. К счастью для моего приложения, у каждого действия есть соответствующий запрос, но я мог себе представить, что в более крупном приложении это привело бы к большому количеству шаблонов для небольшого выигрыша.