//debugger; 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 в объект } } function reducer(state, {type, ШО, СКОКА, БАБЛО}){ //объект action деструктуризируется на три переменных if (!state){ //начальная уборка в ларьке: return { пиво: {count: 100, price: 30}, чипсы:{count: 100, price: 25}, сиги: {count: 100, price: 35}, касса:{count: 0, change: 0}, // касса: 0, при покупках увеличивается } } if (type === 'КУПИТЬ'){ //если тип action - КУПИТЬ, то: //проверить на: //наличие товара как такового (есть ли ключ в объекте) //количество денег в action //наличие нужного количества товара. //и только при соблюдении этих условий обновлять state. if((state[ШО]['count'] - СКОКА) < 0 ) { const div = document.getElementById('message'); div.innerText = `столько ${ШО} нет в наличии, есть ${state[ШО]['count']}`; setTimeout( () => div.innerText = '', 2500); return state; } if ((БАБЛО - СКОКА* state[ШО]['price']) < 0) { const div = document.getElementById('message'); div.innerText = `надо добавитть ${СКОКА * state[ШО]['price'] - БАБЛО} грн.`; setTimeout( () => div.innerText = '', 2500); return state; } if (state[ШО]) { return { ...state, //берем все что было из ассортимента [ШО]: { ...state[ШО], count: state[ШО]['count'] - СКОКА, } , ['касса']: { ...state['касса'], count: state['касса']['count'] + (СКОКА * state[ШО]['price']), change: БАБЛО - СКОКА * state[ШО]['price'], } //и уменьшаем то, что покупается на количество } } } return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть } const store = createStore(reducer); for (let [key, value] of Object.entries(store.getState())) { if(key === 'касса') { continue; } let option = document.createElement('option'); option.innerHTML = `${key}`; goods.append(option); } function viewStore () { const table = document.createElement('table'); table.id = 'table'; document.body.prepend(table); const tr = document.createElement('tr'); table.append(tr); const th1 = document.createElement('th'); th1.innerText = 'Товар'; tr.append(th1); const th2 = document.createElement('th'); th2.innerText = 'Количество товара'; tr.append(th2); const th3 = document.createElement('th'); th3.innerText = 'Цена'; tr.append(th3); for (let [key, value] of Object.entries(store.getState())) { const tr = document.createElement('tr'); const th = document.createElement('th'); th.style.width = '150px'; table.append(tr); tr.appendChild(th).innerHTML = `${key}`; for (let [key1, value1] of Object.entries(value)) { const td = document.createElement('td'); td.style.width = '70px'; tr.appendChild(td).innerHTML =`${value1}`; } } } viewStore(); function deleteTable () { const table = document.getElementById('table'); table.remove(); } store.subscribe(deleteTable); store.subscribe(viewStore); //надо бы напилить цикл, который в select напихивает ассортимент. //возможно, если вы собираетесь выводить (и обновлять) количество, //это надо делать где в subscribe, иначе оно не будет обновлять количество const купи = (ШО, СКОКА, БАБЛО) => ({type: 'КУПИТЬ', ШО, СКОКА, БАБЛО}); buy.onclick = () => { let select = document.getElementById('goods'); let valueSelect = select.options[select.selectedIndex].text; let input = document.getElementById('quantity'); let valueInput = input.value; let cash = document.getElementById('cash').value; store.dispatch({type:'КУПИТЬ', ШО: `${valueSelect}`, СКОКА: `${valueInput}`, БАБЛО: `${cash}`}); setTimeout(() => document.getElementById('quantity').value = '', 2500); setTimeout(() => document.getElementById('cash').value = '', 2500); }; //достает выбранный товар и количество из DOM + // store.dispatch(купи(....,....)) + //запомнит функцию во внутреннем массиве cbs. //она будет запущена при любом успешном dispatch const unsubscribe = store.subscribe(() => console.log(store.getState())) //setTimeout(unsubscribe, 10000) //отпишемся через 10 секунд, например //происходит запуск редьюсера, который создает новый state. //dispatch запускает всех подписчиков из массива cbs // function smth(){ // const h1 = document.createElement('h1') // shop.append(h1) // store.subscribe(() => h1.innerText = store.getState().пиво) // h1.innerText = store.getState().пиво // } // smth() // smth() //setTimeout(() => store.dispatch({type: 'КУПИТЬ', ШО: 'пиво', СКОКА: 3}), 5000)