Вас может удивить, что Redux можно использовать независимо, без таких фреймворков, как React. На самом деле вы можете использовать Redux с чистым кодом JavaScript, который дает ценную информацию о функциональности библиотеки. В этом кратком руководстве я покажу, как создать простое приложение, содержащее метку, текстовое поле и две кнопки увеличения и уменьшения:
Наше приложение поддерживает числовое значение в своем состоянии, что позволяет увеличивать или уменьшать его. Для простоты я предоставлю весь код в одном файле HTML.
Шаг 1 :
Начнем со структуры HTML для нашего приложения:
<!DOCTYPE html> <html> <head> <title>Redux Tutorial</title> </head> <body> <h1>Number: <span id="numberDisplay">1</span></h1> <br> <input type="text" id="amountInput" placeholder="Enter amount (default: 1)"> <br> <button id="increaseBtn">Increase</button> <button id="decreaseBtn">Decrease</button> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.1.1/redux.min.js"></script> <script> const numberDisplay = document.getElementById('numberDisplay'); const increaseBtn = document.getElementById('increaseBtn'); const decreaseBtn = document.getElementById('decreaseBtn'); const amountInput = document.getElementById('amountInput'); // The rest of the code will be added here. </script> </body> </html>
Шаг 2:
Давайте перейдем к определению нашего состояния, которое напоминает объект JSON, в котором хранятся все наши данные. Однако для этого простого приложения состояние состоит только из одного целого числа: const initialState = 1;
Шаг 3:
В Redux мы воздерживаемся от прямого изменения нашего состояния. Вместо этого мы отправляем сообщения в хранилище через действия, состоящие из типов и полезных данных. Действия служат в качестве запросов к хранилищу для соответствующего обновления состояния. В нашем примере приложения у нас есть два действия: increment
и decrement
. Эти действия передают намерение увеличить или уменьшить числовое значение состояния.
// Redux actions with defined types const INCREMENT = 'INCREMENT'; const DECREMENT = 'DECREMENT'; // Action creators with a default value for the amount parameter const increment = (amount = 1) => ({ type: INCREMENT, payload: amount, }); const decrement = (amount = 1) => ({ type: DECREMENT, payload: amount, });
В этом коде мы определяем два действия Redux: INCREMENT
и DECREMENT
, которые действуют как идентификаторы для разных типов действий. Создатели действий, increment
и decrement
, создают и возвращают действия, которые содержат как тип действия (либо INCREMENT
, либо DECREMENT
), и полезную нагрузку (необязательное количество). Полезная нагрузка представляет собой значение, на которое должно увеличиваться или уменьшаться состояние, и по умолчанию оно равно 1, если значение не указано.
Шаг 4:
В Redux редьюсеры — это чистые функции, которые принимают текущее состояние и действие в качестве параметров, а затем возвращают новое состояние в зависимости от типа действия. Если тип действия соответствует одному из случаев в операторе switch, редьюсер применяет соответствующее преобразование к состоянию. В противном случае он возвращает текущее состояние без изменений.
// The numberReducer function takes the current state and an action as parameters. // It returns a new state based on the action type. const numberReducer = (state = initialState, action) => { switch (action.type) { case INCREMENT: // If the action type is INCREMENT, add the action's payload to the current state. return state + action.payload; case DECREMENT: // If the action type is DECREMENT, subtract the action's payload from the current state. return state - action.payload; default: // For any other action type, return the current state without changes. return state; } };
В этом редьюсере параметр state
представляет текущее состояние, а параметр action
представляет отправленный объект действия. В зависимости от типа действия редьюсер вычисляет новое состояние, увеличивая или уменьшая текущее состояние с полезной нагрузкой действия. Если тип действия не распознан, он возвращает текущее состояние как есть, гарантируя, что состояние останется неизменным для необработанных действий.
Шаг 5:
Теперь мы определяем хранилище Redux, которое служит краеугольным камнем Redux, используя Redux.createStore
и передавая numberReducer
. Хранилище содержит состояние приложения, разрешает доступ к состоянию через getState()
и предоставляет метод с именем dispatch(action)
для отправки действий, запускающих обновления состояния.
// Creating the Redux store by passing the numberReducer const store = Redux.createStore(numberReducer);
В этом коде хранилище Redux создается с использованием Redux.createStore()
и инициализируется с помощью файла numberReducer
. Это хранилище теперь будет управлять состоянием приложения и обрабатывать обновления состояния на основе отправленных действий.
Теперь мы определяем функцию с именем updateNumberDisplay
, которая берет текущее состояние из хранилища Redux и отображает его на странице. Подписав эту функцию на магазин, она будет автоматически вызываться при каждом изменении состояния, гарантируя, что отображаемый номер всегда актуален.
// Function to update the displayed number based on the current state const updateNumberDisplay = () => { const number = store.getState(); numberDisplay.textContent = number; }; // Subscribe the updateNumberDisplay function to the store store.subscribe(updateNumberDisplay);
В этом коде функция updateNumberDisplay
извлекает текущее состояние из хранилища Redux, используя store.getState()
. Затем он обновляет содержимое элемента numberDisplay
полученным состоянием, гарантируя, что отображаемое число отражает текущее состояние.
Вызывая store.subscribe(updateNumberDisplay)
, вы указываете магазину выполнять функцию updateNumberDisplay
при каждом изменении состояния. Этот механизм подписки обеспечивает синхронизацию пользовательского интерфейса с состоянием и позволяет обновлять отображаемое число в режиме реального времени всякий раз, когда отправляются действия и изменяется состояние.
Шаг 6:
Мы определили две вспомогательные функции, increaseNumber
и decreaseNumber
, для обработки событий нажатия кнопок «Увеличить» и «Уменьшить» соответственно. Эти функции извлекают ввод из текстового поля amountInput
и отправляют соответствующее действие (increment
или decrement
) с извлеченной суммой. Если действительный ввод не предоставлен, действие по умолчанию отправляется с количеством 1.
// Helper function to handle the "Increase" button click const increaseNumber = () => { const amount = parseInt(amountInput.value); if (!isNaN(amount)) { // Dispatch increment action with the provided amount store.dispatch(increment(amount)); } else { // Dispatch increment action with default amount of 1 store.dispatch(increment()); } }; // Helper function to handle the "Decrease" button click const decreaseNumber = () => { const amount = parseInt(amountInput.value); if (!isNaN(amount)) { // Dispatch decrement action with the provided amount store.dispatch(decrement(amount)); } else { // Dispatch decrement action with default amount of 1 store.dispatch(decrement()); } }; // Event listeners to call the helper functions when buttons are clicked increaseBtn.addEventListener('click', increaseNumber); decreaseBtn.addEventListener('click', decreaseNumber);
С этими вспомогательными функциями и прослушивателями событий нажатие кнопок «Увеличить» или «Уменьшить» вызовет соответствующие действия для обновления состояния. Предоставленное входное значение в текстовом поле amountInput
определяет величину, на которую увеличивается или уменьшается состояние, при этом 1 является значением по умолчанию, если не предоставлено допустимого ввода.
Шаг 7:
Сначала будет вызываться функция updateNumberDisplay()
для отображения начального состояния в пользовательском интерфейсе при запуске приложения. Это гарантирует, что значение состояния будет показано до того, как будут нажаты какие-либо кнопки.
// Initial update: Display the initial state without any buttons clicked updateNumberDisplay();
Летний:
В этом кратком руководстве мы изучили основы Redux, создав простое приложение JavaScript. Приложение имело метку, текстовое поле и две кнопки для увеличения или уменьшения числового состояния.
В Redux представление (пользовательский интерфейс) создает действия через создателей действий и отправляет их в хранилище. Действия несут информацию о том, какую операцию необходимо выполнить. Когда хранилище получает действие, оно передает его вместе с текущим состоянием редюсеру.
Редьюсер отвечает за получение текущего состояния и действия в качестве входных данных и создание нового состояния на основе типа действия и полезной нагрузки. Он выполняет необходимые вычисления и возвращает обновленное состояние.
Как только состояние обновляется, магазин уведомляет все подписанные представления об изменениях. Представления, подписавшиеся на хранилище, получают информацию об обновлении состояния и могут получить новое состояние с помощью метода getState()
. Это позволяет представлениям обновлять свой пользовательский интерфейс, чтобы отразить новое состояние, гарантируя, что пользовательский интерфейс остается синхронизированным с данными приложения.
В Redux данные передаются однонаправленно, что обеспечивает четкий и предсказуемый процесс. Представления запускают действия, которые, в свою очередь, обновляют состояние. Затем обновленное состояние уведомляет представления (в порядке, напоминающем шаблон Observer) о необходимости повторного рендеринга. Этот однонаправленный поток данных является фундаментальным элементом дизайна Redux, обеспечивающим организованный подход к управлению состоянием, который значительно упрощает рассуждения и обработку сложностей в больших приложениях.
Промежуточное программное обеспечение в контексте Redux — это функции, которые перехватывают и изменяют действия и состояние до того, как они достигнут редукторов. Они предоставляют способ расширить поведение Redux и позволяют добавить дополнительные функции в процесс отправки. Промежуточное ПО находится между диспетчером действий и редюсером, что позволяет выполнять дополнительные задачи, такие как ведение журнала, обработка асинхронных операций или изменение действий.
// Middleware const loggerMiddleware = (store) => (next) => (action) => { console.log('Dispatching:', action); const result = next(action); console.log('Next State:', store.getState()); return result; }; // Create the Redux store with the reducer and middleware const store = Redux.createStore(numberReducer, Redux.applyMiddleware(loggerMiddleware));
Теперь полный код:
<!DOCTYPE html> <html> <head> <title>Redux Tutorial</title> </head> <body> <h1>Number: <span id="numberDisplay">1</span></h1> <br> <input type="text" id="amountInput" placeholder="Enter amount (default: 1)"> <br> <button id="increaseBtn">Increase</button> <button id="decreaseBtn">Decrease</button> <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.1.1/redux.min.js"></script> <script> // Get references to HTML elements const numberDisplay = document.getElementById('numberDisplay'); const increaseBtn = document.getElementById('increaseBtn'); const decreaseBtn = document.getElementById('decreaseBtn'); const amountInput = document.getElementById('amountInput'); // Initial state of the application const initialState = 1; // Redux actions const INCREMENT = 'INCREMENT'; const DECREMENT = 'DECREMENT'; // Action creators with a default value for the amount const increment = (amount = 1) => ({ type: INCREMENT, payload: amount, }); const decrement = (amount = 1) => ({ type: DECREMENT, payload: amount, }); // Redux reducer const numberReducer = (state = initialState, action) => { switch (action.type) { case INCREMENT: return state + action.payload; case DECREMENT: return state - action.payload; default: return state; } }; // Create the Redux store with the reducer const store = Redux.createStore(numberReducer); // Function to update the displayed number based on the current state const updateNumberDisplay = () => { const number = store.getState(); numberDisplay.textContent = number; }; // Subscribe the updateNumberDisplay function to the store store.subscribe(updateNumberDisplay); // Helper function to handle the "Increase" button click const increaseNumber = () => { const amount = parseInt(amountInput.value); if (!isNaN(amount)) { store.dispatch(increment(amount)); } else { // Default to 1 if no valid input or empty store.dispatch(increment()); } }; // Helper function to handle the "Decrease" button click const decreaseNumber = () => { const amount = parseInt(amountInput.value); if (!isNaN(amount)) { store.dispatch(decrement(amount)); } else { // Default to 1 if no valid input or empty store.dispatch(decrement()); } }; // Event listeners to call the helper functions when buttons are clicked increaseBtn.addEventListener('click', increaseNumber); decreaseBtn.addEventListener('click', decreaseNumber); // Initial update: Display the initial state without any buttons clicked updateNumberDisplay(); </script> </body> </html>