В этом посте мы напишем упрощенную версию магазина Redux, чтобы понять, как он работает.

Магазин

Store - это центральный репозиторий, в котором хранится состояние вашего приложения.

CreateStore

Сначала мы создаем функцию createStore(), которая вернет хранилище, содержащее 4 части.

1. The store state
2. getState
3. subscribe (listening to changes on the state)
4. dispatch (updating the state)

Каждый раз, когда вы вызываете createStore(), вы возвращаете объект, представляющий хранилище, которое содержит:

1. a way to getting state.
2. listening to changes on the state.
3. updating the state

Что касается состояния, оно не будет публично доступным, но вы можете взаимодействовать с ним, используя публичные методы, о которых мы говорили выше.

Итак, сначала нам нужен какой-то контейнер, который хранит внутреннее состояние, которое хранилище может изменить или получить к нему доступ с помощью 3 методов.

function createStore() {
  let state;
}

getState

Теперь, когда это состояние локально доступно функции createStore(), нам нужно создать способ взаимодействия с этим состоянием.

function createStore() {
  let state;
  function getState() {
    return state;
  }
  return {
    getState,
  };
}

Таким образом, когда пользователь создает хранилище и хочет получить доступ к состоянию, он может сделать это, вызвав getState ().

подписаться

Следующий шаг - заставить пользователя прислушиваться к изменениям состояния.

Мы делаем это, создавая переменную с именем `listeners`, которая изначально будет пустым массивом.

Каждый раз, когда вызывается `subscribe ()`, он получает функцию обратного вызова слушателя. И внутри мы вызываем `listeners`, который представляет собой массив, который мы создали, и нажимаем функцию обратного вызова слушателя, которая была получена при вызове подписки на этот массив.

function createStore() {
  let state;
  let listeners = [];
  function getState() {
    return state;
  }
  function subscribe(listener) {
    listeners.push(listener);
  }
  return {
    getState,
    subscribe,
  };
}

Итак, внутри `createStore ()` нам нужно отслеживать каждый раз, когда пользователь вызывает `store.subscribe ()`, и отслеживать эти переданные функции, чтобы при изменении состояния мы просматривали список функций и вызывали каждую из них. .

function createStore() {
  let state;
  let listeners = [];
  function getState() {
    return state;
  }
  function subscribe(listener) {
    listeners.push(listener);
    return function () {
      listeners = listeners.filter(function (listenerItem) {
        return listenerItem !== listener;
      });
    };
  }
  return {
    getState,
    subscribe,
  };
}

когда пользователь вызывает .subscribe, он возвращает функцию (функцию отмены подписки), и когда эта функция вызывается, мы хотим продолжить и удалить слушателя, который был передан для подписки из массива наших слушателей.

Другими словами, когда пользователь вызывает `.subscribe ()` и передает функцию слушателя, она будет помещена в массив слушателей, и они вернут функцию в результате вызова `.subscribe ()`.

Если они вызывают возвращаемую функцию, она фильтрует массив слушателей и удаляет функцию слушателя.

отправлять

Далее будет обновление состояния хранилища, поскольку мы хотим повысить предсказуемость, мы хотели бы указать тип событий, которые могут обновлять состояние, эти события называются «действиями».

«Действие» - это просто объект, который представляет событие, которое собирается изменить состояние нашего магазина. Действие должно иметь свойство `type`, чтобы указать тип выполняемого действия, кроме структуры на ваше усмотрение.

// action example
{
  type: 'ADD_TODO',
  payload: {
    todo: {
        id: 0,
        name: 'Write a post about Redux'
    }
  }
}

когда действие происходит внутри нашего приложения, мы хотим взять полезную нагрузку из входящего действия и добавить ее в состояние нашего приложения.

Это будет сделано внутри функции `reducer`, которая представляет собой чистую функцию, которая принимает текущее состояние и действие и в зависимости от типа действия будет указывать, как изменяется состояние.

Итак, теперь всякий раз, когда мы вызываем `dispatch ()`, он будет выполнять действие, а внутри него мы вызываем функцию редуктора, которая принимает текущее состояние и действие и собирается получить нам новое состояние, которое затем мы можем обновить внутри .

Всякий раз, когда мы обновляем состояние, нам нужно перебрать слушателей и вызвать их, чтобы они знали, что состояние было обновлено.

function dispatch(action) {
  state = reducer(state, action);
  listeners.forEach(function (listener) {
    return listener();
  });
}

и вот весь магазин вместе

function createStore(reducer) {
  let state;
  let listeners = [];
  function getState() {
    return state;
  }
  function subscribe(listener) {
    listeners.push(listener);
    return function () {
      listeners = listeners.filter(function (listenerItem) {
        return listenerItem !== listener;
      });
    };
  }
  function dispatch(action) {
    state = reducer(state, action);
    listeners.forEach(function (listener) {
      return listener();
    });
  }
  return {
    getState,
    subscribe,
    dispatch,
  };
}

Пример

и ниже приведен пример использования методов хранилища

// reducer function - example
function todos(state = [], action) {
  if (action.type === 'ADD_TODO') {
    return state.concat([action.payload]);
  }
  return state;
}
// create new store
const store = createStore(todos);
// to listen to the changes - something like a logger
const unsubscribe = store.subscribe(() => {
  console.log('state: ', store.getState());
});
// to update the state
store.dispatch({
  type: 'ADD_TODO',
  payload: {
    todo: {
      id: 0,
      name: 'Write a post about Redux',
    },
  },
});