Я сделал еще несколько копаний, и вот как я обошел проблему.
Действие можно создать, не привязывая его к SliceCaseReducer : (Обратите внимание, что созданное getData
ниже это не действие само по себе, а ActionCreator ).
common.ts
import { createAction } from '@reduxjs/toolkit';
export const getData = createAction<number>('getData');
getData
уже приготовлено для отправки из FunctionComponent, если задана правильная полезная нагрузка:
component.tsx
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useParams } from 'react-router';
import { getData } from './state/common';
const User: React.FC = (): React.ReactElement => {
const { userId } = useParams();
const dispatch = useDispatch();
useEffect((): void => {
dispatch(getData(Number(userId)));
}, []);
return (<>User Component</>);
};
export default UserContainer;
с Sagas
Для получения сага слушайте действие
Saga Effects принимает строковый тип действия для реакции. К счастью, actionCreator s предоставляет свойство type , представляющее определенное строковое имя действия.
saga.ts (слушатель)
import { takeLatest } from 'redux-saga/effects';
import { getData } from './common';
function* userSaga() {
// getData.type could be input to a Saga Effect
yield takeLatest(getData.type, fetchUser); // fetchUser is a worker saga explained below
}
Задание действия в качестве аргумента саги.
Задать действие в качестве аргумента саги немного сложно, мы должны использовать TypeScript's Type Guards . Интересно отметить, что это упоминается и в документации о комплектации . Короче говоря, мы должны использовать actionCreator.match
метод actionCreator, чтобы различить переданное действие до желаемого типа. Таким образом, после различения мы получаем желаемый набор c для полезной нагрузки соответствующего действия.
saga.ts (работник)
import { Action } from '@reduxjs/toolkit';
import { call, put } from 'redux-saga/effects';
import * as userApi from '../../../api/user-api';
import { getData } from './common';
import { getUserSuccess, getUserFailure } from './user';
// Note that we can't directly specify that fetchUser only accepts getData action type.
function* fetchUser(action: Action) {
try {
// getData.match could be used to assert that we are only concerned with getData action type
if (getData.match(action)) {
// Inside the body of if, we get correct static typing
const userId = action.payload;
const fetchedUser = yield call(userApi.getUser, userId);
yield put(getUserSuccess({user: fetchedUser}));
}
} catch (e) {
yield put(getUserFailure(e.message));
}
}