123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- function reducer(state, { type, name, amount, money }) { //объект action деструктуризируется на три переменных
- if (!state) { //начальная уборка в ларьке:
- return {
- products: {
- пиво: {
- amount: 100,
- price: 30,
- },
- чипсы: {
- amount: 100,
- price: 25,
- },
- сиги: {
- amount: 100,
- price: 35,
- }
- },
- balance: {
- amount: 0
- }
- }
- }
- if (type === 'buy') { //если тип action - КУПИТЬ, то:
- if (amount > state.products[name].amount) {
- alert('You have entered more quantity than is available');
- return {
- ...state,
- }
- }
- if (money < amount * state.products[name].price) {
- alert('You don`t have enought money');
- return {
- ...state,
- }
- }
- if (money > amount * state.products[name].price) {
- alert('You gave more money');
- return {
- ...state,
- }
- }
- let updatedProducts = state.products
- let updatedField = updatedProducts[name];
- updatedField.amount -= amount;
- let updatedBalance = state.balance;
- updatedBalance.amount += +money;
- return {
- ...state, //берем все что было из ассортимента
- products: updatedProducts, //и уменьшаем то, что покупается на количество
- balance: updatedBalance,
- }
- }
- return state; //если мы не поняли, что от нас просят в `action` - оставляем все как есть
- }
- function createStore(reducer) {
- let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
- let cbs = []; //массив подписчиков
- const getState = () => state; //функция, возвращающая переменную из замыкания
- const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
- () => cbs = cbs.filter(c => c !== cb)); //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
- const dispatch = action => {
- const newState = reducer(state, action); //пробуем запустить редьюсер
- if (newState !== state) { //проверяем, смог ли редьюсер обработать action
- state = newState; //если смог, то обновляем state
- for (let cb of cbs) cb(); //и запускаем подписчиков
- }
- }
- return {
- getState, //добавление функции getState в результирующий объект
- dispatch,
- subscribe //добавление subscribe в объект
- }
- }
- const store = createStore(reducer);
- //запомнит функцию во внутреннем массиве cbs.
- //она будет запущена при любом успешном dispatch
- const unsubscribe = store.subscribe(() => console.log(store.getState()));
- setTimeout(unsubscribe, 10000); //отпишемся через 10 секунд, например
- const buyAction = (name, amount, money) => ({ type: 'buy', name, amount, money });
- //происходит запуск редьюсера, который создает новый state.
- //dispatch запускает всех подписчиков из массива cbs
- function createTable() {
- let state = store.getState();
- let table = document.getElementById('table');
- table.innerHTML = '';
- let headerRow = document.createElement('tr');
- table.append(headerRow);
- let headerName = document.createElement('th');
- headerName.innerText = 'Name';
- headerRow.append(headerName);
- let headerAmount = document.createElement('th');
- headerAmount.innerText = 'Amount';
- headerRow.append(headerAmount);
- let headerPrice = document.createElement('th');
- headerPrice.innerText = 'Price';
- headerRow.append(headerPrice);
- Object.keys(state.products).forEach(key => {
- let row = document.createElement('tr');
- table.append(row);
- let name = document.createElement('td');
- name.innerText = key;
- row.append(name);
- let amount = document.createElement('td');
- amount.innerText = state.products[key].amount;
- row.append(amount);
- let price = document.createElement('td');
- price.innerText = state.products[key].price;
- row.append(price);
- });
- }
- function createBalance() {
- let state = store.getState();
- let balance = document.getElementById('balance');
- balance.innerHTML = '';
- balance.innerText = `Balance: ${state.balance.amount}`;
- }
- function createForm() {
- let state = store.getState();
- let form = document.getElementById('form');
- form.innerHTML = '';
- let selectLabel = document.createElement('label');
- selectLabel.innerText = 'Select a product:';
- form.append(selectLabel);
- let select = document.createElement('select');
- form.append(select);
- Object.keys(state.products).forEach(key => {
- let option = document.createElement('option');
- option.innerHTML = key;
- select.append(option);
- });
- let inputLabel = document.createElement('label');
- inputLabel.innerText = 'Enter quantity:';
- form.append(inputLabel);
- let amountInput = document.createElement('input');
- form.append(amountInput);
- let moneyInputLabel = document.createElement('label');
- moneyInputLabel.innerText = 'Enter amount:';
- form.append(moneyInputLabel);
- let moneyInput = document.createElement('input');
- form.append(moneyInput);
- let submitButton = document.createElement('button');
- submitButton.innerText = 'Buy';
- form.append(submitButton);
- submitButton.addEventListener('click', () => {
- store.dispatch(buyAction(select.value, amountInput.value, moneyInput.value));
- init();
- })
- }
- function init() {
- createTable();
- createBalance();
- createForm();
- }
- init();
|