web-dev-qa-db-fra.com

Où installer le cookie dans l'application Isomorphic Redux?

J'ai 3 questions générales sur l'application redux et isomorphe:

  • Quel est le meilleur moyen de partager des données 'runtime' entre le client et le serveur? Par exemple, lorsque l'utilisateur a connecté une API distante, je stocke l'objet de session dans des cookies. De cette manière, la prochaine fois le client demande mon serveur frontal, le serveur frontal peut lire les cookies et initialiser le magasin Redux avec sa session précédente. L'inconvénient est que le client doit valider/invalider la session au démarrage (par exemple, dans composantDidMount du composant racine). Devrais-je demander au serveur de session plutôt que de le lire à partir de cookies?
  • Où dois-je exécuter l'opération de stockage de cookies, de créateurs d'action ou de réducteurs? Devrais-je stocker le cookie dans mon réducteur qui gère la session de l'utilisateur?
  • Où dois-je exécuter l'opération de redirection de l'utilisateur (via react-router)? Je veux dire quand mon utilisateur est connecté avec succès, d'où dois-je envoyer l'action de redirection (à partir de loginActionCreator une fois que la promesse de connexion est résolue?, Ailleurs?)

Merci d'avance.

15
Cnode

J'ai réussi à obtenir une structure d'application vraiment soignée. Voici ce que j'ai trouvé pour chaque question:

  • Je partage uniquement entre mon client et le serveur frontal le jeton de serveur d'API via des cookies. Chaque fois que le client demande le site. Le serveur frontal appelle le serveur API pour valider la session. Si ces serveurs sont sur le même réseau, c'est très rapide (<5 ms). Je prélève également quelques données utiles pour le client sur le serveur avant le rendu initial. Je parviens à obtenir mon application chargée et prête (javascript chargé) dans le client en 600ms. C'est assez décent.

  • L'action de stocker le cookie est dans mes créateurs d'actions. Comme l'a dit Ethan Clark, nous devons garder les réducteurs purs. C'est beaucoup plus facile à tester.

  • J'envoie toujours la redirection dans mon créateur de connexion une fois l'utilisateur authentifié. J'imagine qu'il est plus facile de tester que d'envoyer l'action après la résolution de la promesse en composant ou ailleurs.

En fait, garder cela à l'esprit nous permet d'avoir une application vraiment facile à tester (attendez-vous au créateur d'actions où vous devez avoir une tonne d'espions).

J'espère que ça va aider quelqu'un.

Merci d'avoir participé.

6
Cnode

Question 2: vous devez exécuter le cookie stocké dans votre créateur d'action. Les réducteurs doivent rester des fonctions pures.

Je suis vraiment désolé de ne pas connaître les réponses aux questions 1 et 3, mais j'espère que cela aidera!

4
Ethan Clark

Vous devriez probablement diviser vos questions en trois questions de débordement de pile différentes car elles sont toutes un peu différentes. 

Je suis d'accord avec Ethan, vos réducteurs doivent être purs, sans effets secondaires. C'est l'objectif (meilleure pratique) de toute façon. Cependant, Ben Nadel a exploré des questions dans ce sens et a suggéré de créer une couche de flux de travail pour gérer la logique métier plutôt que de placer ce fardeau sur le magasin. Vous devriez consulter son Gestion des données en cache local avec Redux dans AngularJS article pour plus d'informations à ce sujet. 

2
Chris Geirman

Les cookies sont synchrones - vous pouvez soit vous hydrater et vous abonner à votre magasin, soit créer un méta-réducteur qui enveloppe le réducteur avant de l'ajouter à createStore. Voici un exemple rapide des deux ci-dessous: 

//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  })
0
evanjmg