web-dev-qa-db-ja.com

Isomorphic ReduxアプリケーションのどこにCookieを設定しますか?

Reduxと同型アプリケーションについて3つの一般的な質問があります。

  • クライアントとサーバー間で「ランタイム」データを共有するための最良の方法は何ですか?たとえば、ユーザーが離れたAPIにログインすると、セッションオブジェクトをCookieに保存します。このようにして、次回クライアントがフロントエンドを要求すると、フロントエンドサーバーはCookieを読み取り、前のセッションでreduxストアを初期化できます。これの欠点は、クライアントが起動時にセッションを検証/無効化する必要があることです(たとえば、ルートコンポーネントのcomponentDidMountで)。 Cookieから読み取るのではなく、セッションサーバー側を要求する必要がありますか?
  • アクションクリエーターまたはレデューサーのどこでCookieの保存操作を実行する必要がありますか?ユーザーセッションを処理するレデューサーにCookieを保存する必要がありますか?
  • (react-routerを介して)ユーザーをリダイレクトする操作をどこで実行する必要がありますか?つまり、ユーザーが正常にログインしたときに、どこからリダイレクトアクションをディスパッチする必要がありますか(ログインが約束されたらloginActionCreatorから)解決されましたか?、どこかで?)

前もって感謝します。

15
Cnode

私はなんとか本当にきちんとしたアプリ構造を手に入れることができました。各質問で私が見つけたものは次のとおりです。

  • クライアントとフロントエンドサーバー間でAPIサーバートークンをCookie経由でのみ共有します。クライアントがサイトを要求するたび。フロントエンドサーバーはAPIサーバーを呼び出してセッションを検証します。これらのサーバーが同じネットワーク上にある場合、それは本当に高速です(<5ms)。また、最初のレンダリングの前に、サーバー上のクライアントに役立つデータをプリフェッチします。 600msでアプリケーションをクライアントにロードして準備(javascriptをロード)することができました。それはかなりまともです。

  • Cookieを保存するアクションは、私のアクション作成者にあります。イーサンクラークが言ったように、私たちはレデューサーを純粋に保つ必要があります。テストははるかに簡単です。

  • ユーザーが認証された後も、サインイン作成者にリダイレクトをディスパッチします。コンポーネントまたは他の場所でpromiseが解決された後にアクションをディスパッチするよりも、テストする方が簡単だと思います。

実際、これを念頭に置いておくと、アプリを非常に簡単にテストできます(大量のスパイが必要なアクションクリエーターを期待してください)。

それが誰かを助けることを願っています。

参加していただきありがとうございます。

6
Cnode

質問2:アクションクリエーターでCookieの保存を実行する必要があります。レデューサーは純粋関数のままでなければなりません。

1と3の答えがわからなくて本当に申し訳ありませんが、これがお役に立てば幸いです。

4
Ethan Clark

質問はすべて少し異なるため、おそらく3つの異なるスタックオーバーフロー質問に分割する必要があります。

私はイーサンに同意します、あなたのレデューサーは副作用のない純粋でなければなりません。とにかく、それが目標(別名ベストプラクティス)です。ただし、Ben Nadelはこれらの方針に沿って質問を調査しており、ストアに負担をかけるのではなく、ビジネスロジックを管理するワークフローレイヤーを作成することを提案しています。詳細については、彼の AngularJSでのReduxを使用したローカルキャッシュデータの管理 の記事を確認する必要があります。

2
Chris Geirman

Cookieは同期的です。ストアにハイドレイトしてサブスクライブするか、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  })
0
evanjmg