Вас может удивить, что 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>