Где установить 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 })