有人可以解释一下这个 reducer 函数头的 reducer 函数吗?

Can someone please explain the reducer function of this reducer function header?

这个问题对某些人来说可能看起来微不足道,但我已经研究了 React、redux 和 javascript 一段时间了。唯一缺少的部分是打字稿。我想了解这段代码中的reducer功能。特别是函数头。

此代码直接取自 visual studio code 2019 react redux template for ASP.net core 3.0 中的示例。特别是 src/store 文件夹中的 WeatherForecast.ts 文件。我找不到很多关于这个例子的文档,因为它很新。据我了解,它使用带有函数链接模式的 redux thunk。我认为让我感到困惑的是打字稿的类型转换。我非常了解模板的其余部分,但我认为是 typescript 让我对 reducer 望而却步。

import { Action, Reducer } from 'redux';
import { AppThunkAction } from './';

// -----------------
// STATE - This defines the type of data maintained in the Redux store.

export interface WeatherForecastsState {
    isLoading: boolean;
    startDateIndex?: number;
    forecasts: WeatherForecast[];
}

export interface WeatherForecast {
    dateFormatted: string;
    temperatureC: number;
    temperatureF: number;
    summary: string;
}

// -----------------
// 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.

interface RequestWeatherForecastsAction {
    type: 'REQUEST_WEATHER_FORECASTS';
    startDateIndex: number;
}

interface ReceiveWeatherForecastsAction {
    type: 'RECEIVE_WEATHER_FORECASTS';
    startDateIndex: number;
    forecasts: WeatherForecast[];
}

// 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 = RequestWeatherForecastsAction | ReceiveWeatherForecastsAction;

// ----------------
// ACTION CREATORS - These are functions exposed to UI components that will trigger a state transition.
// They don't directly mutate state, but they can have external side-effects (such as loading data).

export const actionCreators = {
    requestWeatherForecasts: (startDateIndex: number): AppThunkAction<KnownAction> => (dispatch, getState) => {
        // Only load data if it's something we don't already have (and are not already loading)
        const appState = getState();
        if (appState && appState.weatherForecasts && startDateIndex !== appState.weatherForecasts.startDateIndex) {
            fetch(`api/SampleData/WeatherForecasts?startDateIndex=${startDateIndex}`)
                .then(response => response.json() as Promise<WeatherForecast[]>)
                .then(data => {
                    dispatch({ type: 'RECEIVE_WEATHER_FORECASTS', startDateIndex: startDateIndex, forecasts: data });
                });

            dispatch({ type: 'REQUEST_WEATHER_FORECASTS', startDateIndex: startDateIndex });
        }
    }
};

// ----------------
// REDUCER - For a given state and action, returns the new state. To support time travel, this must not mutate the old state.

const unloadedState: WeatherForecastsState = { forecasts: [], isLoading: false };

export const reducer: Reducer<WeatherForecastsState> = (state: WeatherForecastsState | undefined, incomingAction: Action): WeatherForecastsState => {
    if (state === undefined) {
        return unloadedState;
    }

    const action = incomingAction as KnownAction;
    switch (action.type) {
        case 'REQUEST_WEATHER_FORECASTS':
            return {
                startDateIndex: action.startDateIndex,
                forecasts: state.forecasts,
                isLoading: true
            };
        case 'RECEIVE_WEATHER_FORECASTS':
            // Only accept the incoming data if it matches the most recent request. This ensures we correctly
            // handle out-of-order responses.
            if (action.startDateIndex === state.startDateIndex) {
                return {
                    startDateIndex: action.startDateIndex,
                    forecasts: action.forecasts,
                    isLoading: false
                };
            }
            break;
    }

    return state;
};

没有错误。我只需要了解这些函数头的语义即可。

这是对 reducer 的 async 操作的常用结构,但使用的是打字稿。

基本上,您将数据类型定义为顶部的 interfaces,这些只是定义您希望传递的数据类型的对象。

然后,你就有了 action 和 reducer。 这些的实现与常规 react-redux 完全相同。但是,您正在实施 async 操作(使用 fetch 进行异步调用),因此您还需要使用 redux-thunk 及其来自打字稿的类型 AppThunkAction.

因此,您需要指定 'thing' 每个函数期望传递的(数​​据类型)。

如果您需要特定的数据类型(复杂类型),为它创建一个 interface 会很方便。否则,您可以在要分配给它的每个对象的列 (:) 之后重复此复杂类型,但不建议这样做。

例如,如果我希望通过 idnamehobbiestimestamp 的 API 调用得到一个对象,一个接口对于该复杂类型将是:

export interface dataFromAPICall {
    id: number;
    name: string;
    hobbies?: string[];
    timestamp: number;
}

在这种情况下,hobbies 是可选的 (?),它需要字符串数组 ['football', 'sky', 'bodyboard surfing']

对于流行库中的复杂类型,通常已经定义了这些类型,例如 redux 中的 AppThunkAction 或 React 中的 ReactNode

希望对您有所帮助!