为什么这个Redux Saga Selector不工作?我似乎无法访问州

时间:2018-01-19 22:55:39

标签: typescript react-redux redux-saga

我正在使用Redux,Saga和使用Typescript在React中开发应用程序。

应用程序结构设置为每个主要顶级容器组件在Store目录中都有一个相应的文件,用于定义它的动作创建者,减少者和传奇。

当应用程序启动时,所有Reducer都是从Store文件组合而来的,并且Sagas被组合成一个共同的rootSaga函数。

一切正常,但现在我正在尝试使用选择器将一些状态属性加载到我的一个Sagas中。我没有收到任何错误,但我的选择器功能没有返回我的状态值。

如果我尝试在Store文件中使用getState()函数,我会收到一个Typescript错误'找不到名称getState'。

显然,我没有在我的Store文件中包含正确的库,或者我没有通过正确的命名空间调用状态函数,但我无法弄清楚是什么问题。

我从Thunk中间件切换到使用Saga。当Thunk连接到应用程序时,我可以在Store文件中使用getState。

这是包含我的动作创建者,减少者和传奇的商店文件。

我的选择器功能也在文件中(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'。

知道我做错了吗?

2 个答案:

答案 0 :(得分:1)

select的参数是回调:

const callback = state => state.asVersionQueue.versionQueueFilter
const versionQueueFilters = yield select(callback)

答案 1 :(得分:0)

看起来我误解了传奇选择是如何运作的。

在我的职能中:

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;

我传入我的选择的函数没有提供任何东西,但是将它留空会返回整个状态树。