1

现在,我正在尝试通过 Redial 获取应用程序服务器端的初始状态。

Redial 触发一个纯对象操作,redux-saga 监听/等待该操作,然后启动异步请求。

但问题是,Redial 没有承诺解决 redux-saga 何时完成,因为它正在调度一个纯对象。

零件

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

我认为可以通过以下方式完成:

首先,您需要在本地添加商店。(代码取自重拨自述文件)

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 执行结果,而不是一遍又一遍地检查 redux 存储状态,直到状态与那些 if(...) 语句匹配,也许你可以使用 redux 存储和外部侦听器运行 saga,然后那些重拨hooks 不需要了解您的商店结构。

于 2016-12-14T14:51:40.357 回答
0

有一种相当优雅的方法可以做到这一点。首先,您需要为您的 saga 任务创建一个注册表(请记住,运行中间件的.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获取该任务的承诺并将其添加到数组中。

通过调用getPromise,您将收到一个承诺,该承诺将在所有添加的任务完成后解决。它永远不会被拒绝,因为您很可能不希望失败的获取导致拒绝 - 您仍然希望以错误状态呈现您的应用程序。

这就是您可以将其与以下内容结合使用的方式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());
  },
};

从这里开始,您可以像往常一样使用 sagas。这应该让你有能力做你正在尝试的事情。您可以进一步抽象它以允许跨代码拆分块和其他事物动态注册 saga。getPromise任务注册表已经为这些用例工作,通过在实际解决承诺之前检查自上次调用以来新注册的任务。

于 2017-01-03T01:53:09.740 回答