Может кто-нибудь объяснить, пожалуйста, функцию редуктора этого заголовка функции редуктора? - PullRequest
0 голосов
/ 07 июля 2019

Для некоторых этот вопрос может показаться тривиальным, но я уже некоторое время изучаю реакции, редуксы и javascript. Единственная недостающая часть - машинопись. Я хочу понять функцию редуктора в этом фрагменте кода. В частности, заголовок функции.

Этот код непосредственно взят из примера в Visual Studio код 2019 реагирует на редукционный шаблон для ASP.net core 3.0. В частности, файл WeatherForecast.ts в папке src / store. Я не смог найти много документации об этом примере, так как он довольно новый. Насколько я понимаю, он использует Redux Thunk с шаблоном цепочки функций. То, что я думаю, смущает меня, приведение типов с машинописью. Я хорошо понимаю остальную часть шаблона, но я думаю, что именно машинопись выбивает меня из-за редуктора.

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;
};

Нет ошибок. Мне просто нужно понять семантику этих заголовков функций.

1 Ответ

0 голосов
/ 07 июля 2019

Это обычная структура действия async для редуктора, но с использованием машинописи.

По сути, вы определяете типы данных как interfaces сверху, это просто объекты, определяющие, какой тип данных вы ожидаете пройти.

Тогда у вас есть действие и редуктор. Их реализация точно такая же, как и в обычном реакт-редуксе. Однако вы реализуете действие async (выполняете асинхронный вызов с использованием fetch), поэтому вам также нужно использовать redux-thunk и его тип из машинописи AppThunkAction.

Следовательно, вам нужно указать, какую «вещь» (тип данных) ожидает передать каждая функция.

Если вам нужен определенный тип данных (сложный тип), удобно создать для него interface. В противном случае вы можете повторить этот сложный тип, следуя столбцам (:) каждого объекта, которому вы хотите его назначить, но это не рекомендуется.

Например, если я ожидаю объект от вызова API с id, name, hobbies и timestamp, интерфейс для этого сложного типа будет:

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

В этом случае хобби является необязательным (?) и он ожидает и массив строк ['football', 'sky', 'bodyboard surfing'].

В случае сложных типов в популярных библиотеках обычно эти типы уже определены, например AppThunkAction в избыточном или ReactNode в React.

Надеюсь, это поможет!

...