为啥这个 Redux Saga Selector 不工作?我似乎无法访问状态
Posted
技术标签:
【中文标题】为啥这个 Redux Saga Selector 不工作?我似乎无法访问状态【英文标题】:Why isn't this Redux Saga Selector working? I can't seem to access state为什么这个 Redux Saga Selector 不工作?我似乎无法访问状态 【发布时间】:2018-06-29 06:17:45 【问题描述】:我正在使用 Redux、Saga 和 Typescript 开发一个 React 应用程序。
应用程序结构的设置使得每个主要***容器组件在 Store 目录中都有一个相应的文件,用于定义它的动作创建者、reducers 和 sagas。
当应用启动时,所有的 reducer 都从 Store 文件中组合起来,而 Sagas 组合成一个通用的 rootSaga 函数。
除了现在我尝试使用选择器将一些状态属性加载到我的 Sagas 中之外,一切都很好。我没有收到任何错误,但我的选择器函数没有返回我的状态值。
如果我尝试在我的 Store 文件中使用 getState() 函数,我会收到 Typescript 错误“找不到名称 getState”。
很明显,我没有在我的 Store 文件中包含正确的库,或者我没有通过正确的命名空间调用 state 函数,但我不知道出了什么问题。
我从 Thunk 中间件切换到使用 Saga。当 Thunk 连接到应用程序时,我可以在 Store 文件中使用 getState。
这是包含我的 action creators、reducers 和 sagas 的 Store 文件。
我的选择器函数也在文件中(export const getVersionQueueFilters):
import fetch, addTask from 'domain-task';
import Action, Reducer, ActionCreator from 'redux';
import takeLatest, takeEvery from "redux-saga"
import call, put, take, race, select from "redux-saga/effects"
import * as moment from 'moment';
// -----------------
// STATE - This defines the type of data maintained in the Redux store.
export interface ASVersionQueueState
queuedVersions: QueuedVersion[];
versionQueueFilter: VersionQueueFilter;
eventsFilterList: SelectListItem[];
employeesFilterList: SelectListItem[];
gridIsLoading: boolean;
versionQueueRefresh: boolean;
error: boolean;
export interface QueuedVersion
VersionCode: string;
VersionQualifier: string;
VersionID: string;
ProductID: string;
PieceName: string;
PrintClass: string;
FirstInhomeDate: string;
AccountID: string;
AccountExecutive: string;
AccountManager: string;
ArtManager: string;
AdUID: string;
Status: string;
Queue: string;
DueDateOverride: string;
IsLocked: string;
export interface VersionQueueFilter
StartDate: string;
EndDate: string;
PieceType: Array<string>;
EventType: Array<string>;
EventID: string;
Employee: string;
export interface SelectListItem
OptionName: string;
OptionVal: string;
export let DefaultVersionQueueFilter =
StartDate: moment().subtract(30, 'days').format('YYYY-MM-DD'),
EndDate: moment().format('YYYY-MM-DD'),
PieceType: ['impactpc'],
EventType: ['special'],
EventID: '',
Employee: '12345'
// Version Queue polling delay value
let versionQueuePollDelay: number = 10000; // Delay in milliseconds
// -----------------
// ACTIONS - These are serializable (hence replayable) descriptions of state transitions.
// They do not themselves have any side-effects; they just describe something that is going to happen.
// Use @typeName and isActionType for type detection that works even after serialization/deserialization.
interface PollVersionsAction
type: 'POLL_VERSIONS';
versionQueueFilter: VersionQueueFilter;
versionQueueRefresh: boolean;
interface PollRequestVersionsAction
type: 'POLL_REQUEST_VERSIONS';
versionQueueFilter: VersionQueueFilter;
versionQueueRefresh: boolean;
interface PollRequestVersionsSuccessAction
type: 'POLL_REQUEST_VERSIONS_SUCCESS';
versionQueueFilter: VersionQueueFilter;
receivedVersions: QueuedVersion[];
versionQueueRefresh: boolean;
interface PollRequestVersionsErrorAction
type: 'POLL_REQUEST_VERSIONS_ERROR';
// Declare a 'discriminated union' type. This guarantees that all references to 'type' properties contain one of the
// declared type strings (and not any other arbitrary string).
type KnownAction = PollVersionsAction | PollRequestVersionsSuccessAction | PollRequestVersionsErrorAction;
// ----------------
// ACTION CREATORS - These are functions exposed to UI components that will trigger a state transition.
// They don't directly mutate state
export const actionCreators =
pollVersions: () =>
return type: 'POLL_VERSIONS', versionQueueFilter: getVersionQueueFilters, versionQueueRefresh: true
,
pollRequestVersions: (versionQueueFilter: VersionQueueFilter, versionQueueRefresh: boolean) =>
return type: 'POLL_REQUEST_VERSIONS', versionQueueFilter: versionQueueFilter, versionQueueRefresh: versionQueueRefresh
,
pollRequestVersionsSuccess: (versionQueueFilter: VersionQueueFilter, versionQueueRefresh: boolean, data: QueuedVersion[]) =>
return type: 'POLL_REQUEST_VERSIONS_SUCCESS', versionQueueFilter: versionQueueFilter, receivedVersions: data, versionQueueRefresh: versionQueueRefresh
,
pollRequestVersionsError: () =>
return type: 'POLL_REQUEST_VERSIONS_ERROR'
;
// ----------------
// REDUCER - For a given state and action, returns the new state. To support time travel, this must not mutate the old state.
const unloadedState: ASVersionQueueState = gridIsLoading: false, versionQueueRefresh: false, queuedVersions: [], versionQueueFilter: DefaultVersionQueueFilter, eventsFilterList: [], employeesFilterList: [], error: false ;
export const reducer: Reducer<ASVersionQueueState> = (state: ASVersionQueueState, incomingAction: Action) =>
const action = incomingAction as KnownAction;
switch (action.type)
case 'POLL_VERSIONS':
return
...state,
versionQueueFilter: action.versionQueueFilter,
versionQueueRefresh: action.versionQueueRefresh,
gridIsLoading: true
case 'POLL_REQUEST_VERSIONS_SUCCESS':
// Only accept the incoming data if it matches the most recent request. This ensures we correctly
// handle out-of-order responses.
if (action.versionQueueFilter === state.versionQueueFilter && action.versionQueueRefresh === state.versionQueueRefresh)
return
...state,
queuedVersions: action.receivedVersions,
versionQueueRefresh: action.versionQueueRefresh,
gridIsLoading: false
break;
case 'POLL_REQUEST_VERSIONS_ERROR':
return
...state,
error: true
default:
// The following line guarantees that every action in the KnownAction union has been covered by a case above
const exhaustiveCheck: never = action;
return state || unloadedState;
;
// Sagas
// Saga Watchers
export const sagas = [
takeEvery('POLL_VERSIONS', fetchPollVersionsAsync)
]
// Selector Function
export const getVersionQueueFilters = (store: ASVersionQueueState) => store.versionQueueFilter;
// Utility function to delay effects
export function delay(delayMS: number)
const promise = new Promise(resolve =>
setTimeout(() => resolve(true), delayMS)
);
return promise;
export function* versionPoller()
const versionQueueFilters = yield select(getVersionQueueFilters);
try
yield call(delay, versionQueuePollDelay);
yield put(actionCreators.pollVersions() );
catch (error)
// cancellation error
return;
export function* watchVersionPoller()
while (true)
yield take('POLL_REQUEST_VERSIONS_SUCCESS');
yield call(versionPoller);
export function* fetchPollVersionsAsync(action: PollVersionsAction)
try
yield put(actionCreators.pollRequestVersions(action.versionQueueFilter, action.versionQueueRefresh));
const data = yield call(() =>
return fetch('api/Versions')
.then(res => res.json())
);
yield put(actionCreators.pollRequestVersionsSuccess(action.versionQueueFilter, action.versionQueueRefresh, data));
catch (error)
yield put(actionCreators.pollRequestVersionsError());
选择器用于saga函数“versionPoller()”。
基本上,我会轮询我的 API 以获取任何更新的数据,但它至少需要传递一组默认的过滤器值。我想为此使用当前处于状态的过滤器值。
我也尝试将我的选择器函数定义为:
export const getVersionQueueFilters = getState().ASVersionQueueState.versionQueueFilter;
当我这样做时,我收到错误“找不到名称 getState”。
知道我做错了什么吗?
【问题讨论】:
【参考方案1】:select
的参数是回调:
const callback = state => state.asVersionQueue.versionQueueFilter
const versionQueueFilters = yield select(callback)
【讨论】:
【参考方案2】:看来我误解了传奇选择的工作原理。
在我的功能中:
export function* versionPoller()
const versionQueueFilters = yield select(getVersionQueueFilters);
try
yield call(delay, versionQueuePollDelay);
yield put(actionCreators.pollVersions() );
catch (error)
// cancellation error
return;
我应该做的是:
const state = yield select();
const versionQueueFilters = state.asVersionQueue.versionQueueFilter;
我传递给我的选择的函数没有提供任何东西,而是将其留空返回整个状态树。
【讨论】:
您是正确的,不带参数调用 select() 会返回整个状态树,但我认为这不是最初错误的原因。正如@dancerphil 回答的那样,您的选择器有一个错误,它应该访问store.asVersionQueue.versionQueueFilter
,但您只是访问了store.asVersionQueueFilter
以上是关于为啥这个 Redux Saga Selector 不工作?我似乎无法访问状态的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用 redux-thunk 或 redux-saga 进行 fetches?
为啥 redux-saga 使用 put 方法而不是 dispatch?
如何使用 redux-saga-test-plan 测试选择器功能
我的减速机应该处理@@ redux-saga-test-plan / INIT动作吗?
什么时候应该使用 Redux Saga 而不是 Redux Thunk,什么时候应该使用 Redux Thunk 而不是 Redux Saga?