Автор оригинала: FreeCodeCamp Community Member.
Fabian Terh
Эта статья разделена на 4 раздела:
- Тип проверки действий redux, создатели действия и редукторы
- Установка определений библиотеки потока
- Тип Проверка состояния приложения
- Тип Проверка магазина redux и отправка
Хотя на первом разделе есть куча гидов, которые являются неармымиленными полезными, я обнаружил только о незначительности статьи 3 и 4. После длительной сессии поиска Google, дайвинга в исходный код и проб и ошибку, я решил поставить Вместе то, что я узнал, и пишу этот учебный пособие как однократное руководство по типу проверки вашего ADTACT + Redux + Read-redux приложение с потоком.
1. Введите проверку действий redux, создатели действия и редукторы
Действия
Действия Redux по существу являются объектами Vanilla JavaScript с обязательным Тип свойство:
// This is an action{ type: 'INCREASE_COUNTER', increment: 1}Следуя лучшим практикам, вы можете определить и использовать Константы типа действий вместо. Если это так, вышеупомянутый фрагмент, вероятно, будет выглядеть что-то подобное:
const INCREASE_COUNTER = 'INCREASE_COUNTER';
// This is an action{ type: INCREASE_COUNTER, increment: 1}Проверка типа проста (мы имеем дело с регулярным JavaScript здесь):
type $action = { type: 'INCREASE_COUNTER', increment: number};Обратите внимание, что вы не можете заменить буквальный тип строки с константой Увеличить_counter Отказ Это Ограничение потока самого.
Действия Создатели
Поскольку Action Creators – это просто функции, которые возвращают действия, мы все еще имеем дело с регулярным JavaScript. Вот как может выглядеть проверяемое действие типа
function increaseCounter(by: number): $action { return { type: INCREASE_COUNTER, // it's okay to use the constant here increment: by };}Редукторы
Редукторы – это функции, которые обрабатывать действия Отказ Они получают государство и действие и вернуть новое состояние. На этом этапе важно подумать о том, как будет выглядеть ваше государство (государственная форма). В этом очень простом примере формы состояния состоит только один ключ счетчик который берет на себя Номер Тип стоимости:
// State shape{ counter: } И поэтому ваш редуктор может выглядеть так:
const initialState = { counter: 0 };function counter(state = initialState, action) { switch (action.type) { case INCREASE_COUNTER: return Object.assign({}, state, { counter: action.increment + state.counter }); default: return state; }};Примечание: в этом конкретном примере Object.Assign ({}, состояние, {...}) избыточно, потому что магазин состоит только из 1 пары ключа/значения. Я мог бы просто вернуть последний аргумент на функцию. Однако я включил полную реализацию для правильности.
Набрав состояние и редуктор достаточно просто. Вот набранный Версия вышеуказанного фрагмента:
type $state = { +counter: number};const initialState: $state = { counter: 0 };function counter( state: $state = initialState, action: $action): $state { switch (action.type) { case INCREASE_COUNTER: return Object.assign({}, state, { counter: action.increment + state.counter }); default: return state; }};Установка определений библиотеки потока
Поток Определения библиотеки (или libdefs) предоставляют определения типа для сторонних модулей. В этом случае мы используем React, Redux и React-redux. Вместо того, чтобы набрать эти модули и их функции вручную, вы можете установить определения их типа, используя набранный поток :
npm install -g flow-typed
// Automatically download and install all relevant libdefsflow-typed install
// Orflow-typed install@ // e.g. redux@4.0.0
Определения библиотеки установлены в набранный поток Папка, которая позволяет потоку работать из коробки без какой-либо дополнительной конфигурации ( Детали ).
Тип Проверка состояния приложения
Раньше мы уже набрали состояние, как это:
type $state = { +counter: number};Пока это работает для простого примера, как то, как указано выше, он разрушается после того, как ваше состояние становится значительно большим. Вы должны были бы вручную редактировать Тип $ State Каждый раз, когда вы представляете новый редуктор или измените существующий. Вы также не хотели бы сохранить все ваши редукторы в одном файле. Вместо этого вы хотите сделать реконструкцию своих редукторов в отдельные модули и использовать redux Коммунатории
Так как в центре внимания этой статьи на Тип проверки Реакция/redux/red-redux приложение, а не на здании один, я собираюсь предположить, что вы знакомы с Коммунатории функция. Если нет, отправляйтесь на Учебник Redux чтобы узнать все об этом.
Предположим, мы вводим новую пару действий/редукторов в отдельном модуле:
// playSong.js
export const PLAY_SONG = 'PLAY_SONG';
// Typing the actionexport type $playSongAction = { type: 'PLAY_SONG', song: ?string};// Typing the action creatorexport function playSong(song: ?string): $playSongAction { return { type: PLAY_SONG, song: song };};// Typing arg1 and the return value of the reducer [*1]export type $song = ?string;
// Typing the state [*1]export type $songState = { +song: $song};// [*1][*2]const initialValue: $song = null;
// Typing the reducer [*1][*3]function song( state: $song = initialValue, action: $playSongAction): $song { switch (action.type) { case PLAY_SONG: return action.song; default: return state; }};[* 1]: Если мы используем Коммунатории Функция, важно отметить, что Ваш редуктор больше не должен возвращать состояние, а скорее ценность к ключу в состоянии Отказ В связи с этим я думаю Учебник Redux Мне немного не хватает четкости, так как он не утверждает это явно, хотя это ясно из примерных фрагментов кода.
[* 2]: Редукторы не могут вернуть undefined поэтому мы должны согласиться на null Отказ
[* 3]: Поскольку редуктор больше не получают и возвращает состояние в форме {Песня: строка} , а скорее ценность к песня Ключ в объекте штата, нам нужно изменить типы его первого аргумента и возврата от $ Songstate к $ песня Отказ
Мы изменим и рефактору inwaresecounter также:
// increaseCounter.js
export const INCREASE_COUNTER = 'INCREASE_COUNTER';
export type $increaseCounterAction = { type: 'INCREASE_COUNTER', increment: number};export function increaseCounter(by: number): $action { return { type: INCREASE_COUNTER, increment: by };};export type $counter = number;
export type $counterState = { +counter: $counter};const initialValue: $counter = 0;
function counter( state: $counter = initialValue, action: $increaseCounterAction): $counter { switch (action.type) { case INCREASE_COUNTER: return action.increment + state; default: return state; }};Теперь у нас есть 2 пары действия/редуктора.
Мы можем создать новый Государство Тип для хранения типа состояния нашего приложения:
export type State = $songState & $counterState;
Это поток Тип пересечения и эквивалентно:
export type State = { song: $song, counter: $counter};Если вы не хотите создавать $ Songstate и $ CounterState Только для использования в наборе пересечения набрав состояние приложения Государство Это совершенно хорошо, – иди со вторым внедрением.
Тип Проверка магазина redux и отправка
Я обнаружил, что поток сообщил ошибки в моих контейнерах (в контексте контейнер/компонент Paradigm ).
Could not decide which case to select. Since case 3 [1] may work but if it doesn't case 6 [2] looks promising too. To fix add a type annotation to dispatch [3].
Это было в связи с моим mapdispatchtopops функция. Шкафы 3 и 6 следующие:
// flow-typed/npm/react-redux_v5.x.x.js
// Case 3declare export function connect< Com: ComponentType<*>, A, S: Object, DP: Object, SP: Object, RSP: Object, RDP: Object, CP: $Diff<$Diff;, RSP>, RDP> >( mapStateToProps: MapStateToProps , mapDispatchToProps: MapDispatchToProps): (component: Com) => ComponentType;
// Case 6declare export function connect< Com: ComponentType<*>, S: Object, SP: Object, RSP: Object, MDP: Object, CP: $Diff, RSP> >( mapStateToProps: MapStateToProps , mapDispatchToPRops: MDP): (component: Com) => ComponentType<$Diff& SP>;
Я не знаю, почему возникает эта ошибка. Но как об ошибке намекает, набрав Отправка исправляет это. И если мы печатаем Отправка мы могли бы также набирать магазин слишком.
Я не мог найти много документации по этому аспекту ввода приложения Redux/React-redux. Я узнал, погружение в либедефы и глядя на Исходный код для других проектов (хотя и демонстрационный проект). Если у вас есть какие-либо идеи, пожалуйста, дайте мне знать, чтобы я мог обновить этот пост (с правильной атрибуцией, конечно).
Тем временем я обнаружил, что это работает:
import type { Store as ReduxStore, Dispatch as ReduxDispatch} from 'redux';// import any other variables and types you may need,// depending on how you organized your file structure.
// Reproduced from earlier onexport type State = { song: $song, counter: $counter};export type Action = | $playSongAction | $increaseCounterAction
export type Store = ReduxStore;
export type Dispatch = ReduxDispatch;
Направляясь в ваши контейнерные модули, вы можете затем перейти к типу mapdispatchtopops Как следует: const mapdispatchtopons = (рассылка: рассылка) => {... };
Обертывание
Это был довольно длинный пост, и я надеюсь, что вы нашли это полезным. Я написал его частично из-за невырассудимости ресурсов, касающихся более поздних разделов этой статьи (и отчасти организовать мои мысли и консолидировать то, что я узнал).
Я не могу гарантировать, что руководство в этой статье следует наилучшими практиками, либо концептуально звучат, или даже на 100% правильно. Если вы обнаружите какие-либо ошибки или проблемы, пожалуйста, дайте мне знать!