Автор оригинала: Alex Moldovan.
Как ваша фасоль приложений в интерфейс? Как вы убедитесь, что код, который вы пишете, достаточно пригодны 6 месяцев?
Redux Взял мир предельной разработки штормом в 2015 году и зарекомендовал себя как стандарт – даже за рамки реагирования.
В компании, где я работаю, мы недавно закончили рефакторирую довольно большую кодовую базу RACT, добавляя Redux вместо Рефлюкс Отказ
Мы сделали это, потому что продвижение вперед было бы невозможно без хорошо структурированного приложения и хорошего набора правил.
CodeBase более двух лет, и Рефлюкс Был там с самого начала. Мы должны были изменить код, который не был тронут более года и был довольно запутанным с компонентами реагирования.
Основываясь на работе, которую мы сделали на проекте, я собрал Это репо Объясняя наш подход в организации нашего кода Redux.
Когда вы узнаете о Redux и ролях действий и редукторов, вы начинаете с очень простых примеров. Большинство учебных пособий сегодня не переходят на следующий уровень. Но если вы строете что-то с помощью Redux, который более сложный список TODO, вам понадобится более умный способ масштабирования вашей кодовой базы со временем.
Кто-то однажды сказал, что Наимение вещей является одной из самых сложных рабочих мест в информатике. Я не мог согласиться больше. Но структурирующие папки и организация файлов являются близкой секунду.
Давайте рассмотрим, как мы приблизились к организации кода в прошлом.
Функция против функции
Существует два установленных подхода структурирующих применений: функция- Первый и Функция – первая Отказ
Один левый ниже вы можете увидеть структуру функциональной первой папки. Справа вы можете увидеть первый подход.
Функция – сначала означает, что ваши каталоги верхнего уровня названы в честь целей файлов внутри. Так у вас есть: Контейнеры , Компоненты , Действия , Редукторы , так далее.
Это совсем не масштабируется. По мере роста вашего приложения вы добавляете больше функций, вы добавляете файлы в одни и те же папки. Таким образом, вы в конечном итоге при необходимости прокрутите одну папку, чтобы найти ваш файл.
Проблема также связана с соединением папок вместе. Один поток через ваше приложение, вероятно, потребует файлов из всех папок.
Одним из преимуществ этого подхода является то, что он изолярует – в нашем случае – реагировать от redux. Поэтому, если вы хотите изменить государственную библиотеку управления, вы знаете, какие папки вам нужно коснуться. Если вы измените библиотеку просмотра, вы можете сохранить свои папки Redux Intact.
Особенно-первое означает, что каталоги верхнего уровня названы в честь основных функций приложения: Продукт , Корзина , сессия .
Этот подход масштабируется намного лучше, потому что каждая новая функция поставляется с новой папкой. Но у вас нет разделения между компонентами реагирования и Redux. Изменение одного из них в долгосрочной перспективе – очень сложная работа.
Кроме того, у вас есть файлы, которые не принадлежат ни к какой-либо функции. Вы в конечном итоге с папкой общий или Общий, Потому что вы хотите повторно использовать код во многих функциях в вашем приложении.
Лучшие из двух миров
Хотя не в объеме этой статьи я хочу прикоснуться к этой единой идее: Всегда отдельные файлы управления государством из файлов пользовательских интерфейсов.
Подумайте о своем приложении в долгосрочной перспективе. Представьте себе, что происходит с кодовой базой, когда вы переключаетесь с Реагировать в другую библиотеку. Или подумайте, как будет использовать вашу кодовую базу Реантэтировать Параллельно с веб-версией.
Наш подход Начинается из необходимости выделить React Code в одну папку – называемые Views – и код Redux в отдельной папке – называемый redux.
Этот первый уровень первого уровня дает нам гибкость для организации двух отдельных частей приложения, совершенно разные.
Внутри папки Views мы предпочитаем функциональный подход в структурирующих файлах. Это очень естественно в контексте реагирования: Страницы , Макеты , Компоненты, усилители и т.п.
Чтобы не сходить с ума с количеством файлов в папке, у нас может быть разделена на основе функций, находящаяся на основе на основе каждого из этих папок.
потом Внутри папки Redux …
Введите RE-утки
Каждая особенность приложения должна отображаться для отдельных действий и редукторов, поэтому имеет смысл идти на соответствующий подход.
Оригинал Утки модульный подход Это хорошая упрощение для Redux и предлагает структурированный способ добавления каждой новой функции в вашем приложении.
Тем не менее, мы хотели изучить немного, что происходит, когда приложения весы. Мы поняли, что один файл для функции становится слишком загроможденным и трудно поддерживать в долгосрочной перспективе.
Вот как Re-Ducks родился Отказ Решение было разделено каждую функцию в утка папка.
duck/ ├── actions.js ├── index.js ├── operations.js ├── reducers.js ├── selectors.js ├── tests.js ├── types.js ├── utils.js
Папка утина должна:
- Содержит всю логику для обработки только одна концепция в вашем приложении, например: Продукт , Корзина , сессия , так далее.
- иметь
index.jsФайл, который экспортирует в соответствии с оригинальными правилами утки. - Держите код с аналогичными целями в одном файле, например Редукторы , Селекторы и Действия
- содержать Тесты связанные с уткой.
Для этого примера мы не использовали никакой абстракции, построенной на вершине redux. При строительстве программного обеспечения важно начать с наименьшего количества абстракций. Таким образом, вы убедитесь, что стоимость ваших абстракций не перевешивает преимущества.
Если вам нужно убедить себя, что абстракции могут быть плохими, посмотреть это Удивительный разговор Cheng Lou Отказ
Давайте посмотрим, что попадет в каждый файл.
Типы
Типы Файл содержит имена действий, которые вы отправляете в вашем приложении. В качестве хорошей практики вы должны попытаться примерить имена, основанные на функции, к которой они принадлежат. Это помогает при отладке более сложных приложений.
const QUACK = "app/duck/QUACK";
const SWIM = "app/duck/SWIM";
export default {
QUACK,
SWIM
};Действия
Этот файл содержит все функции Creator Action.
import types from "./types";
const quack = ( ) => ( {
type: types.QUACK
} );
const swim = ( distance ) => ( {
type: types.SWIM,
payload: {
distance
}
} );
export default {
swim,
quack
};Обратите внимание, как все действия представлены функциями, даже если они не параметризованы. Последовательный подход более чем необходим в большой кодовой базе.
Операции
Чтобы представлять цепные операции, вам нужен redux промежуточное программное обеспечение Улучшить функцию отправки. Некоторые популярные примеры: Redux-Thunk , Redux-Saga или redux-наблюдаемый Отказ
В нашем случае мы используем Redux-Thunk Отказ Мы хотим отделить Thunks от создателей действий, даже с стоимостью написания дополнительного кода. Таким образом, мы определяем операцию как обертку над действиями.
Если операция передает только одно действие – на самом деле не использует Redux-Thunk – мы пересылаем функцию Action Creator. Если операция использует Thunk, он может отправлять много действий и цепочек их с обещаниями.
import actions from "./actions";
// This is a link to an action defined in actions.js.
const simpleQuack = actions.quack;
// This is a thunk which dispatches multiple actions from actions.js
const complexQuack = ( distance ) => ( dispatch ) => {
dispatch( actions.quack( ) ).then( ( ) => {
dispatch( actions.swim( distance ) );
dispatch( /* any action */ );
} );
}
export default {
simpleQuack,
complexQuack
};Позвоните им операции, Thunks, Sagas, Epics, это ваш выбор. Просто найдите соглашение об именах и придерживаться его.
В конце, когда мы обсудим индекс , мы увидим, что операции являются частью публичного интерфейса утки. Действия инкапсулированы, операции выставлены.
Редукторы
Если у функции есть больше граней, вы обязательно должны использовать несколько редукторов для обработки разных частей формы состояния. Кроме того, не бойтесь использовать Коммунатории столько, сколько нужно. Это дает вам большую гибкость при работе со сложной формой состояния.
import { combineReducers } from "redux";
import types from "./types";
/* State Shape
{
quacking: bool,
distance: number
}
*/
const quackReducer = ( state = false, action ) => {
switch( action.type ) {
case types.QUACK: return true;
/* ... */
default: return state;
}
}
const distanceReducer = ( state = 0, action ) => {
switch( action.type ) {
case types.SWIM: return state + action.payload.distance;
/* ... */
default: return state;
}
}
const reducer = combineReducers( {
quacking: quackReducer,
distance: distanceReducer
} );
export default reducer;В крупномасштабном применении ваше государственное дерево будет не менее 3 уровня. Функции редукторов должны быть максимально небольшими и обрабатывать только простые конструкции данных. Коммунатории Утилита функция – это все, что вам нужно для создания гибкой и поддерживаемой формы состояния.
Проверьте Полный пример проекта и посмотри, как Коммунатории используется. Один раз в Редукторы.js файлы, а затем в store.js Файл, где мы собрали все дерево штата.
Селекторы
Вместе с операциями селекторы являются частью публичного интерфейса утки. Разделение между операциями и селекторами напоминает CQRS Pattern Отказ
Функции селектора имеют кусочек состояния приложения и вернуть некоторые данные на основе этого. Они никогда не вводят никаких изменений в состояние приложения.
function checkIfDuckIsInRange( duck ) {
return duck.distance > 1000;
}
export default {
checkIfDuckIsInRange
};Показатель
Этот файл указывает, что экспортируется из папки утиной. Так и будет:
- Экспорт в качестве по умолчанию Редуктор Функция утки.
- Экспорт в качестве названия экспортирует селекторы и операции.
- Экспортируйте типы, если они нужны в других утках.
import reducer from "./reducers";
export { default as duckSelectors } from "./selectors";
export { default as duckOperations } from "./operations";
export { default as duckTypes } from "./types";
export default reducer;Тесты
Преимущество использования redux и структуры уток состоит в том, что вы можете написать тесты рядом с кодом, который вы тестируете.
Тестирование вашего кода Redux довольно прямо вперед:
import expect from "expect.js";
import reducer from "./reducers";
import actions from "./actions";
describe( "duck reducer", function( ) {
describe( "quack", function( ) {
const quack = actions.quack( );
const initialState = false;
const result = reducer( initialState, quack );
it( "should quack", function( ) {
expect( result ).to.be( true ) ;
} );
} );
} );Внутри этого файла вы можете написать тесты для редукторов, операций, селекторов и т. Д.
Я мог бы написать целую другую статью о преимуществах тестирования вашего кода, их так много. Просто сделай это!
Так что это
Приятная часть о RE-Ducks состоит в том, что вы используете тот же шаблон для всего вашего кода Redux.
Сплит на основе функций для кода Redux намного более гибкий и масштабируемый, поскольку ваша база Code приложения растет. И на основе функций разделен для просмотров работает при создании небольших компонентов, которые передаются на приложение.
Вы можете ознакомиться с полным React-redux пример кодовой базы здесь Отказ Просто имейте в виду, что репо все еще находится под активным развитием.
Как вы структурируете свои приложения Redux? Я с нетерпением жду, чтобы услышать некоторые отзывы об этом подходе, который я представлял.
Если вы нашли эту статью полезную, нажмите на зеленое сердце ниже, и я узнаю, что мои усилия не зря.
Оригинал: “https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/”