hw_22_03 thunk.html 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. <head>
  2. store Thunk
  3. </head>
  4. <body>
  5. <script>
  6. class Store {
  7. #reducer;
  8. #state;
  9. #cbs = []
  10. get state() {
  11. return this.#state;
  12. }
  13. getState() { return this.#state; } //функция, возвращающая переменную из замыкания
  14. subscribe(cb) {
  15. this.#cbs.push(cb); //запоминаем подписчиков в массиве
  16. return (cb) => {
  17. this.#cbs = this.#cbs.filter(c => c !== cb)
  18. }
  19. } //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  20. dispatch(action) {
  21. /*
  22. */
  23. const newState = this.#reducer(this.#state, action) //пробуем запустить редьюсер
  24. if (newState !== this.#state) { //проверяем, смог ли редьюсер обработать action
  25. this.#state = newState //если смог, то обновляем state
  26. for (let cb of this.#cbs) cb() //и запускаем подписчиков
  27. }
  28. }
  29. constructor(reducer) {
  30. this.#reducer = reducer;
  31. this.#state = this.#reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
  32. }
  33. }
  34. class StoreThunk extends Store {
  35. dispatch(action) {
  36. if (typeof action === 'function') { //если action - не объект, а функция
  37. return action(this.dispatch.bind(this), this.getState.bind(this)) //запускаем эту функцию и даем ей dispatch и getState для работы
  38. }
  39. super.dispatch(action);
  40. }
  41. }
  42. const seller = (state, { type, item, amount, cash, price }) => {
  43. if (state === undefined) {
  44. state = {
  45. beer: { amount: 20, price: 10 },
  46. vodka: { amount: 10, price: 30 },
  47. cigars: { amount: 100, price: 20 },
  48. cashbox: 0,
  49. }
  50. }
  51. if (type === 'BUY' &&
  52. item in state &&
  53. typeof amount == "number" &&
  54. typeof cash == "number" &&
  55. state[item].amount >= amount &&
  56. amount > 0 &&
  57. cash > 0 &&
  58. state[item].price <= cash / amount) { //если тип action - КУПИТЬ, то:
  59. return {
  60. ...state, //берем все что было из ассортимента
  61. [item]: { amount: state[item].amount - amount, price: state[item].price }, //и уменьшаем то, что покупается на количество
  62. cashbox: state.cashbox + amount * state[item].price,
  63. }
  64. }
  65. return state;
  66. }
  67. let store = new StoreThunk(seller);
  68. const unsubscribe = store.subscribe(() => console.log(store.getState()))
  69. store.dispatch((dispatch, getStore) => dispatch({ type: 'BUY', item: 'cigars', amount: 3, cash: 58 }));
  70. store.dispatch((dispatch, getStore) => dispatch({ type: 'BUY', item: 'vodka', amount: 3, cash: 92 }));
  71. unsubscribe();
  72. console.log(store.state);
  73. </script>
  74. </body>