Компоненты ReactJS Flux Utils

Интересно статья который описывает 4 основных класса, открытых в Flux Utils.

  • Магазин
  • ReduceStore
  • MapStore (удалено из 3.0.0)
  • Контейнер

Но это не очень ясно, что следует использовать для определенных ситуаций. Есть только 2 примера для ReduceStore и Container, но нет примеров для других, к сожалению.

Не могли бы вы объяснить базовое использование этих 4 компонентов: , когда и , где они должны использоваться в реальной жизни?

Расширенные ответы и примеры кода будут действительно оценены!

UPDATE:

MapStore был удален, начиная с 3.0.0

Ответ 1

Пролистав код и прочитав документацию по методу, вот что я могу решить (я сам не использовал эти классы, так как использую другие фреймворки Flux).

На самом деле полезно пойти в почти обратном порядке для них.

Контейнер

Это не подкласс FluxStore потому что, что неудивительно, это не магазин. Container - это класс-оболочка для ваших компонентов пользовательского интерфейса React, который автоматически извлекает состояние из указанных хранилищ.

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

Мой компонент будет выглядеть примерно так (полученный из примера кода, который они предоставляют):

import {Component} from 'react';
import {Container} from 'flux/utils';

import {LoggedInUsersStore} from /* somewhere */;
import {UserListUI} from /* somewhere */;

class UserListContainer extends Component {
  static getStores() {
    return [UsersStore];
  }

  static calculateState(prevState) {
    return {
      loggedInUsers: LoggedInUsersStore.getState(),
    };
  }

  render() {
    return <UserListUI counter={this.state.counter} />;
  }
}

const container = Container.create(UserListContainer);

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

Я полагаю, что это довольно прямое продолжение принципов кодирования Facebook React, в которых каждый бит пользовательского интерфейса находится в высокоуровневом "контейнере". Отсюда и название.

Когда использовать

  • Если данный компонент React полностью зависит от состояния нескольких явных хранилищ.
  • Если это не зависит от реквизита сверху. Контейнеры не могут принимать реквизиты.

ReduceStore

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

Например, лямбда (a) => { return a * a; } (a) => { return a * a; } чисто: оно детерминировано и не имеет побочных эффектов. (a) => { echo a; return a; } (a) => { echo a; return a; } нечист: у него есть побочный эффект (печать a). (a) => { return Math.random(); } (a) => { return Math.random(); } нечисто: оно недетерминировано.

Целью ReduceStore является упрощение: сделав свой магазин чистым, вы можете сделать определенные предположения. Поскольку сокращения являются детерминированными, каждый может выполнить сокращения в любой момент и получить тот же результат, поэтому отправка потока действий практически идентична отправке необработанных данных. Аналогично, отправка необработанных данных совершенно разумна, поскольку вам не было гарантировано никаких побочных эффектов: если вся моя программа сделана из ReduceStore s, и я перезаписываю состояние одного клиента на состояние другого (вызывая необходимые перерисовки), я гарантирую отличная функциональность. Ничто в моей программе не может измениться из-за действий, а не данных.

В любом случае, ReduceStore должен реализовывать только методы, явно указанные в его документации. getInitialState() должен определять начальное состояние, getInitialState() reduce(state, action) должен преобразовывать state заданного action (а не использовать this вообще: это было бы недетерминированным/иметь побочные эффекты), и getState() & areEqual(one,two) должен обрабатывать отделение необработанного состояния от возвращенного состояния (чтобы пользователь не мог случайно изменить его).

Например, счетчиком будет разумный ReduceStore:

class TodoStore extends ReduceStore {
    getInitialState() {
        return 0;
    }

    reduce(state, action) {
        switch(action.type) {
            case 'increment':
                return state + 1;
            case 'decrement':
                return state - 1;
            case 'reset':
                return 0;
            default:
                return state;
    }

    getState() {
        // return 'this._state', which is that one number, in a way that doesn't let the user modify it through something like 'store.getState() = 5'
        // my offhand JS knowledge doens't let me answer that with certainty, but maybe:
        var a = this._state + 1;
        return a - 1;
    }
}

Обратите внимание, что ни одно из преобразований явно не зависит от текущего состояния объекта: они работают только с той переменной state они были переданы. Это означает, что экземпляр хранилища может вычислять состояние для другого экземпляра того же хранилища. Не очень полезно в текущей реализации FB Flux, но все же.

Когда использовать

  • Если вам нравится чисто функциональное программирование (ууу!)
  • и если вам не нравится это достаточно, чтобы использовать рамки явно построенные с этим предположением (перевождите, NuclearJS)
  • и вы можете разумно написать магазин, который является чисто функциональным (большинство магазинов могут, и если они не могут, возможно, имеет смысл подумать об архитектуре немного больше)

Примечание: этот класс не гарантирует, что ваш код является чисто функциональным. Я думаю, что это сломается, если вы сами не проверите это.

Я бы всегда использовал этот магазин. Если только я не смогу использовать...

FluxMapStore [ УСТАРЕЛО ]

Этот класс больше не является частью Flux!

Это подкласс ReduceStore. Это для таких чисто функциональных магазинов, которые оказываются внутри Карт. В частности, карты Immutable.JS (еще одна вещь FB!).

У них есть удобные методы для получения ключей и значений из состояния:

WarrantiesStore.at('extended') а не WarrantiesStore.getState().get('extended').

Когда использовать

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

FluxStore

Это приводит нас к FluxStore: универсальному классу Store и общей реализации концепции Flux Store.

Два других магазина являются его потомками.

Мне кажется, что документация достаточно ясна в отношении его использования, поэтому я оставлю это на этом

Когда использовать

  • Если вы не можете использовать два других класса Store util для хранения ваших данных
  • и вы не хотите катить свой собственный магазин

В моем случае это никогда не будет: я предпочитаю неизменные фреймворки, такие как redux и NuclearJS, потому что мне легче рассуждать. Я забочусь о том, чтобы структурировать свои магазины исключительно функционально. Но если нет, этот класс хорош.