Где установить cookie в приложении Isomorphic Redux?

У меня есть 3 общих вопроса о редукции и изоморфном применении:

  • Каков наилучший способ обмена данными "runtime" между клиентом и сервером? Например, когда пользователь зарегистрировался в удаленном API, я сохраняю объект сеанса в файлах cookie. Таким образом, в следующий раз клиент запрашивает мой интерфейс, интерфейсный сервер может читать файлы cookie и инициализировать хранилище redux с ним предыдущим сеансом. Недостатком этого является то, что клиент должен проверить/аннулировать сеанс при загрузке (например, в компоненте componentDidMount корневого компонента). Должен ли я запрашивать сервер сеанса сервера, а не читать его из файлов cookie?
  • Где я должен выполнять операцию хранения файлов cookie, в создателях действий или в редукторах? Должен ли я хранить файл cookie в моем редукторе, который обрабатывает сеанс пользователя?
  • Где я должен выполнить операцию перенаправления пользователя (через ретранслятор)? Я имею в виду, когда мой пользователь успешно зарегистрирован, откуда я должен отправить действие перенаправления (из loginActionCreator once решение для входа в систему разрешено?, где-то еще?)

Спасибо заранее.

Ответы

Ответ 1

Мне удалось получить очень аккуратную структуру приложения. Вот что я нашел для каждого вопроса:

  • Я разделяю только между моим клиентом и интерфейсом сервера маркер сервера API через файлы cookie. Каждый раз клиент запрашивает сайт. Передний сервер вызывает сервер API для проверки сеанса. Если эти серверы находятся в одной сети, это очень быстро (< 5ms). Я также предваряю некоторые полезные данные для клиента на сервере перед первоначальным рендерингом. Мне удается загружать и загружать мое приложение (загружено javascript) в клиенте в 600 мс. Это довольно прилично.

  • Действие сохранения файла cookie происходит в моих создателях действий. Как сказал Итан Кларк, мы должны поддерживать чистоту редукторов. Это намного легче проверить.

  • Я по-прежнему отправляю перенаправление в моем создателе подписчика после аутентификации пользователя. Я думаю, это легче проверить, чем отправить действие после решения обещания в компоненте или в другом месте.

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

Надеюсь, что это поможет кому-то.

Спасибо за участие.

Ответ 2

Вопрос 2: вы должны выполнить сохранение файлов cookie в своем создателе действия. Редукторы должны оставаться чистыми функциями.

Мне очень жаль, что я не знаю ответов на 1 и 3, но надеюсь, что это поможет!

Ответ 3

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

Я согласен с Этаном, ваши редукторы должны быть чистыми без побочных эффектов. То, что цель (иначе лучшая практика) в любом случае. Тем не менее, Бен Надель изучает вопросы в этом направлении и предлагает создать рабочий поток для управления бизнес-логикой, а не для того, чтобы разместить это бремя в магазине. Чтобы получить дополнительную информацию об этом, вы должны проверить его Управление локально кэшированными данными с помощью Redux в AngularJS".

Ответ 4

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

//first option
 const Cookie = require('js-cookie');
const loadState = (key) => Cookie.getJSON(key);
const saveState = (nextState, key) => Cookie.set(key, nextState);
const persistedState = loadState('todos');
const store = createStore(
  todoApp,
  persistedState
);

store.subscribe(throttle(() => {
  saveState({
    todos: store.getState().todos,
  }, 'todos');
}, 1000));

//second option - meta reducer
// usage  
    const Cookie = require('js-cookie');

    export function cookieMeta (
      key: string,
      reducer: any,
      expiry: Date | number = 365,
      path: string = '/',
      domain: string = window.location.hostname): Function {
      return function(state: any, action: any): any {
        let nextState = reducer(state, action);
        let cookieState = Cookie.getJSON(key);

        if (action.type.includes('DELETE')) {
          Cookie.remove(key);
        } else if (!nextState && cookieState || action.type === '@@redux/INIT') {
          nextState = cookieState;
        } else if (nextState && nextState !== cookieState) {
            Cookie.set(key, nextState, { expires: expiry, path: path, domain: domain, secure: process.env.local });
        }
        return nextState;
      };
    };
// how to implement the meta reducer
import { todos } from './todos';
import { cookieMeta } from './middleware/cookieMeta';
export function TODOS_REDUCER (state: any, action: any) {
    return cookieMeta('todos', todos)(state, action);
}
export const todoApp = combineReducers({ todos: TODOS_REDUCER  })