|
@@ -0,0 +1,85 @@
|
|
|
+<head>
|
|
|
+ store Thunk
|
|
|
+</head>
|
|
|
+
|
|
|
+<body>
|
|
|
+ <script>
|
|
|
+ class Store {
|
|
|
+ #reducer;
|
|
|
+ #state;
|
|
|
+ #cbs = []
|
|
|
+ get state() {
|
|
|
+ return this.#state;
|
|
|
+ }
|
|
|
+ getState() { return this.#state; } //функция, возвращающая переменную из замыкания
|
|
|
+ subscribe(cb) {
|
|
|
+ this.#cbs.push(cb); //запоминаем подписчиков в массиве
|
|
|
+ return (cb) => {
|
|
|
+ this.#cbs = this.#cbs.filter(c => c !== cb)
|
|
|
+ }
|
|
|
+ } //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
|
|
|
+ dispatch(action) {
|
|
|
+ /*
|
|
|
+
|
|
|
+ */
|
|
|
+ const newState = this.#reducer(this.#state, action) //пробуем запустить редьюсер
|
|
|
+ if (newState !== this.#state) { //проверяем, смог ли редьюсер обработать action
|
|
|
+ this.#state = newState //если смог, то обновляем state
|
|
|
+ for (let cb of this.#cbs) cb() //и запускаем подписчиков
|
|
|
+ }
|
|
|
+ }
|
|
|
+ constructor(reducer) {
|
|
|
+ this.#reducer = reducer;
|
|
|
+ this.#state = this.#reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ class StoreThunk extends Store {
|
|
|
+ dispatch(action) {
|
|
|
+ if (typeof action === 'function') { //если action - не объект, а функция
|
|
|
+ return action(this.dispatch.bind(this), this.getState.bind(this)) //запускаем эту функцию и даем ей dispatch и getState для работы
|
|
|
+ }
|
|
|
+ super.dispatch(action);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ const seller = (state, { type, item, amount, cash, price }) => {
|
|
|
+ if (state === undefined) {
|
|
|
+ state = {
|
|
|
+ beer: { amount: 20, price: 10 },
|
|
|
+ vodka: { amount: 10, price: 30 },
|
|
|
+ cigars: { amount: 100, price: 20 },
|
|
|
+ cashbox: 0,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (type === 'BUY' &&
|
|
|
+ item in state &&
|
|
|
+ typeof amount == "number" &&
|
|
|
+ typeof cash == "number" &&
|
|
|
+ state[item].amount >= amount &&
|
|
|
+ amount > 0 &&
|
|
|
+ cash > 0 &&
|
|
|
+ state[item].price <= cash / amount) { //если тип action - КУПИТЬ, то:
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...state, //берем все что было из ассортимента
|
|
|
+ [item]: { amount: state[item].amount - amount, price: state[item].price }, //и уменьшаем то, что покупается на количество
|
|
|
+ cashbox: state.cashbox + amount * state[item].price,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return state;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let store = new StoreThunk(seller);
|
|
|
+
|
|
|
+ const unsubscribe = store.subscribe(() => console.log(store.getState()))
|
|
|
+ store.dispatch((dispatch, getStore) => dispatch({ type: 'BUY', item: 'cigars', amount: 3, cash: 58 }));
|
|
|
+ store.dispatch((dispatch, getStore) => dispatch({ type: 'BUY', item: 'vodka', amount: 3, cash: 92 }));
|
|
|
+ unsubscribe();
|
|
|
+ console.log(store.state);
|
|
|
+
|
|
|
+ </script>
|
|
|
+</body>
|