Автор оригинала: 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% правильно. Если вы обнаружите какие-либо ошибки или проблемы, пожалуйста, дайте мне знать!