0

我正在寻找例如如何使用Next.jsgetInitialProps的钩子来处理redux-observable ajax 史诗。甚至可能吗?

换句话说 - 如何在getInitialProps

import { ajax } from 'rxjs/observable/dom/ajax';

// action creators
const fetchUser = username => ({ type: FETCH_USER, payload: username });
const fetchUserFulfilled = payload => ({ type: FETCH_USER_FULFILLED, payload });

// epic
const fetchUserEpic = action$ =>
  action$.ofType(FETCH_USER)
    .mergeMap(action =>
      ajax.getJSON(`https://api.github.com/users/${action.payload}`)
        .map(response => fetchUserFulfilled(response))
    );

...所以我可以在服务器上获取初始数据。

getInitialProps的文档

4

2 回答 2

0

如果我理解正确,您希望从中分派操作getInitialProps并确保这些操作已完成,以便可以进行渲染。看看这个库https://github.com/mquintal/next-redux-observable它可能会有所帮助。

于 2020-04-17T19:22:30.917 回答
-1

编辑:我最初的回答并没有说得足够清楚,我的意思是在组件(或 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

于 2017-09-24T21:17:35.143 回答