1

現在、アプリケーション サーバー側の初期状態を Redial で取得しようとしています。

リダイヤルは純粋なオブジェクト アクションをトリガーし、redux-saga はそのアクションをリッスン/待機してから、非同期要求を開始します。

しかし問題は、純粋なオブジェクトをディスパッチしているため、redux-saga が完了したときに解決するという約束が Redial にないことです。

成分

const redial = {
   fetch: ({ dispatch }) => dispatch({ type: actionTypes.FETCH_START }),
};

export default class PostList extends Component {
    render() {
        const { posts } = this.props;
        return (
            <div>
                {posts.map(post => <ListItem key={post.id} post={post} />)}
            </div>
        );
    }
}

PostList.propTypes = {
    posts: PropTypes.array.isRequired,
};

export default provideHooks(redial)(connect(mapStateToProps)(PostList));

佐賀

export function *fetch() {
    try {
        yield put({ type: actionTypes.FETCH_START });
        const response = yield call(fakeData);
        yield put({ type: actionTypes.FETCH_SUCCESS, data: response.data });
        yield put({ type: actionTypes.FETCH_PENDING });
    } catch (e) {
        yield put({ type: actionTypes.FETCH_FAIL });
    }
}

export default function *loadPost() {
    yield * takeLatest(actionTypes.FETCH_START, fetch);
}

export default function *rootSaga() {
    yield [
        fork(loadPost),
    ];
}

に接続する方法はありredialますredux-sagaか?

4

2 に答える 2

1

私はそれがこのようにできると思います:

まず、ローカルにストアを追加する必要があります。(コードはリダイヤルの README から取得されます)

const locals = {
  path: renderProps.location.pathname,
  query: renderProps.location.query,
  params: renderProps.params,

  // Allow lifecycle hooks to dispatch Redux actions:
  dispatch,
  store
};

次に、次のように Promise を手動で作成できます。

const redial = {
   fetch: ({ store, dispatch }) => {
       return new Promise((resolve, reject) => {
           const unsubscribe = store.subscribe(()=>{
               if (store.getState()...) { // monitor store state changing by your saga
                   resolve(...) //you probably dont need any result since your container can read them from store directly
                   unsubscribe();
               }
               if (store.getState()....error) {
                   reject(...)
                   unsubscribe();
               }
           });
           dispatch({ type: actionTypes.FETCH_START }),
       }
   }
};

これらのコードはデモンストレーション用です。適切なテストを行わずに本番環境で使用しないでください。

saga の実行結果を監視するには、状態が if(...) ステートメントと一致するまで redux ストアの状態を何度もチェックするよりもエレガントな方法があると思います。おそらく、redux ストアと外部リスナーを使用して saga を実行してから、それらのリダイヤルを実行できます。フックはストア構造について知る必要はありません。

于 2016-12-14T14:51:40.357 に答える
0

これを行うかなりエレガントな方法があります。まず最初に、サガ タスク用のレジストリを作成する必要があります (ミドルウェアの.runメソッドを実行すると、タスク記述子が返されることに注意してください)。

export default class SagaTaskRegistry {
  constructor() {
    this._taskPromises = [];
  }

  addTask(task) {
    if (!this._taskPromises) {
      this._taskPromises = [];
    }
    this._taskPromises.push(task.done);
  }

  getPromise() {
    return new Promise((resolve) => {
      const promises = this._taskPromises;
      if (!promises) {
        resolve();
        return;
      }
      this._taskPromises = undefined;
      Promise.all(promises).then(resolve).catch(resolve);
    }).then(() => {
      const promises = this._taskPromises;
      if (promises) {
        return this.getPromise();
      }
      return undefined;
    });
  }
}

を使用して saga ミドルウェアに新しいタスクを追加する.runと、 が呼び出されますregistryInstance.add(taskDescriptor)。はそのSagaTaskRegistryタスクの promise を取得し、それを配列に追加します。

を呼び出すとgetPromise、追加されたすべてのタスクが終了したときに解決される promise を受け取ります。失敗したフェッチが拒否されることを望まない可能性が高いため、拒否されることはありません。アプリケーションをエラー状態でレンダリングしたい場合もあります。

そして、これはあなたがそれを組み合わせることができる方法ですredial

import createSagaMiddleware from 'redux-saga';
import { applyMiddleware, createStore } from 'redux';
import rootReducer from 'your/root/reducer';
import yourSaga from 'your/saga';

const sagaMiddleware = createSagaMiddleware();
const middleWare = [sagaMiddleware];
const createStoreWithMiddleware = applyMiddleware(...middleWare)(createStore);
const store = createStoreWithMiddleware(rootReducer);
const sagaTaskRegistry = new SagaTaskRegistry();
const sagaTask = sagaMiddleware.run(yourSaga);
sagaTaskRegistry.addTask(sagaTask);

match({ routes, history }, (error, redirectLocation, renderProps) => {
  const locals = {
    path: renderProps.location.pathname,
    query: renderProps.location.query,
    params: renderProps.params,
    dispatch: store.dispatch,
  };

  trigger('fetch', components, locals);

  // Dispatching `END` will force watcher-sagas to terminate,
  // which is required for the task promises to resolve.
  // Without this the server would never render anything.
  // import this from the `redux-saga` package
  store.dispatch(END);

  // The `SagaTaskRegistry` keeps track of the promises we have to resolve
  // before we can render
  sagaTaskRegistry.getPromise().then(...)
});

コンポーネントを単純なフックで装飾できるようになりました:

const hooks = {
  fetch: ({ dispatch }) => {
    dispatch(yourAction());
  },
};

ここから先は、通常どおりサガを使用できます。これにより、あなたがしようとしていることができるようになるはずです。これをさらに抽象化して、コード分割されたチャンクやその他のものにまたがるサガの動的登録を可能にすることができます。タスク レジストリはgetPromise、promise を実際に解決する前に、 への最後の呼び出し以降に新しく登録されたタスクをチェックすることで、これらのユース ケースに対して既に機能しています。

于 2017-01-03T01:53:09.740 に答える