编辑:我最初的回答并没有说得足够清楚,我的意思是在组件(或 getInitialProps)内调度操作并提供某种回调以在完成时通知它通常是不可能的,也不是惯用的.
相反,通常你会派发一个动作,你的 Epics 会处理它(执行副作用)然后他们自己会派发其他动作来触发 Redux 中的状态更改。您的组件将仅根据 Redux 存储的状态更改重新渲染。这就是它的设计方式,无论好坏。
对于那些因此而被否决的人,我很抱歉,这不是 Redux Observable 的设计初衷。Redux Observable 在设计时并未考虑到 Next.js。如果您使用它和 Redux 只是作为获取数据的一种方式,那么它可能比它的价值更重要,而不是仅仅调用fetch()
.
也就是说,软件几乎总是具有延展性的,呵呵。即使不是 RO 的意图,在技术上也可以使某些东西发挥作用。不过,我不推荐它。RO 并非用于提前页面渲染之类的事情,而是用于复杂的客户端交互。你当然可以两者都做!在 getInitialProps 中使用常规的 fetch() 或其他 AJAX 实用程序,然后根据 RO 来满足复杂的客户端要求(如果适用)。
无论哪种方式,现在Next.js 存储库中都有一个示例,说明其他人如何处理它,但我个人并不提倡这种方法。
如果我必须这样做,这是我的:
/* 1. Add something like this to your root reducer
*************************************************/
function lastActionType(state = null, action) {
// If you wanted to, you could store the entire action including the payload,
// but if you ever have actions which have a large payload, it would prevent
// it from being garbage collected until the next action was dispatched.
return action.type;
}
const rootReducer = combineReducers({
lastActionType, // <-- add this
...otherReducers,
});
/* 2. Create a utility to listen for an action
*************************************************/
function waitForAction(store, options) {
return new Promise((resolve, reject) => {
const unsubscribe = store.subscribe(() => {
const state = store.getState();
if (state.lastActionType === options.fulfilled.type) {
unsubscribe();
const value = options.fulfilled.selector(state);
resolve(value);
} else if (state.lastActionType === options.rejected.type) {
unsubscribe();
const value = options.rejected.selector(state);
reject(value);
}
});
});
}
/* 3. Use the utility
*************************************************/
async function getInitialProps() {
// Kick it off
store.dispatch(fetchUser('user123'));
try {
// Wait for it
const user = await waitForAction(store, {
fulfilled: {
type: FETCH_USER_FULFILLED,
selector: (state) => {
// Some sort of state selector for looking up users
return state.user;
},
},
// If you want to have error handling, this might be how you'd do it too.
rejected: {
type: FETCH_USER_REJECTED,
selector: (state) => {
// Some sort of state selector for errors
return state.userError;
},
},
});
return {
user,
...otherPropsYouHave,
};
} catch (e) {
// Handle errors in some way
}
}
要将 redux-observable 与 React 一起使用,您的 UI 组件将调度简单的操作,然后您的 Epics 将监听并响应这些操作。因此,您的组件对 redux-observable 没有直接的了解——它们只是调度操作并连接到存储以接收状态更改。
这是文档中的一个简单 JSBin 示例:https ://jsbin.com/jexomi/edit?js,output
const App = ({ isPinging, ping }) => (
<div>
<h1>is pinging: {isPinging.toString()}</h1>
<button onClick={ping}>Start PING</button>
</div>
);
export default connect(
({ isPinging }) => ({ isPinging }),
{ ping }
)(App);
这里还有一个稍微复杂一点的例子:https ://github.com/redux-observable/redux-observable/tree/master/examples/redux-observable-shopping-cart