Reputation: 557
I have 3 general questions about redux and isomorphic application:
Thanks in advance.
Upvotes: 15
Views: 7138
Reputation: 3790
Cookies are synchronous - you can either hydrate and subscribe to your store or make a meta reducer which wraps around the reducer before it is added to createStore. Here's quick example of both below:
//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 })
Upvotes: 0
Reputation: 557
I managed to get a really neat app structure. Here's what I found for each questions:
I only share between my client and front-end server the API server token via cookies. Each time the client request the site. The front-end server calls the API server to validate the session. If these servers are on the same network it's really fast (< 5ms). I also prefetch some useful data for the client on the server before the initial render. I manage to get my application loaded and ready (javascript loaded) in the client in 600ms. It is pretty decent.
The action of storing the cookie is in my actions creators. As Ethan Clark said, we must keep reducers pure. It's much more easier to test.
I still dispatch the redirect in my signin creator once the user is authenticated. I guess it's easier to test than to dispatch the action after the promise resolution in component or elsewhere.
In fact, keeping this in mind allows us to have an app really easy to test (expect for the actions creator where you must have ton of spies).
Hope it will help someone.
Thanks for participating.
Upvotes: 6
Reputation: 9684
You should probably break your questions up into three different stack overflow questions since they're all a little different.
I agree with Ethan, your reducers should be pure with no side effects. That's the goal (aka best practice) anyway. However, Ben Nadel has been exploring questions along these lines and suggests creating a workflow layer to manage business logic rather than placing that burden on the store. You should check out his Managing Locally Cached Data with Redux in AngularJS article for more information about that.
Upvotes: 2
Reputation: 126
Question 2: you should execute cookie storing in your action creator. Reducers must remain pure functions.
I'm really sorry that I don't know the answers to 1 & 3, but I hope that this helps!
Upvotes: 4