mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
update with-redux-observable example (#4818)
This commit is contained in:
parent
822cc3c863
commit
53853d3fa9
|
@ -47,13 +47,14 @@ probably making initial requests on a server. That's because, the
|
|||
`getInitialProps` hook runs on the server-side before epics have been made available by just dispatching actions.
|
||||
|
||||
However, we can access and execute epics directly. In order to do so, we need to
|
||||
pass them an Observable of an action and they will return an Observable:
|
||||
pass them an Observable of an action together with StateObservable and they will return an Observable:
|
||||
|
||||
```js
|
||||
static async getInitialProps({ store, isServer }) {
|
||||
const state$ = new StateObservable(new Subject(), store.getState());
|
||||
const resultAction = await rootEpic(
|
||||
of(actions.fetchCharacter(isServer)),
|
||||
store
|
||||
state$
|
||||
).toPromise(); // we need to convert Observable to Promise
|
||||
store.dispatch(resultAction)};
|
||||
```
|
||||
|
@ -61,8 +62,8 @@ static async getInitialProps({ store, isServer }) {
|
|||
Note: we are not using `AjaxObservable` from the `rxjs` library; as of rxjs
|
||||
v5.5.6, it will not work on both the server- and client-side. Instead we call
|
||||
the default export from
|
||||
[universal-rx-request](https://www.npmjs.com/package/universal-rx-request) (as
|
||||
`ajax`).
|
||||
[universal-rxjs-ajax](https://www.npmjs.com/package/universal-rxjs-ajax) (as
|
||||
`request`).
|
||||
|
||||
We transform the Observable we get from `ajax` into a Promise in order to await
|
||||
its resolution. That resolution should be a action (since the epic returns
|
||||
|
|
|
@ -9,17 +9,15 @@
|
|||
"author": "tomaszmularczyk(tomasz.mularczyk89@gmail.com)",
|
||||
"dependencies": {
|
||||
"next": "latest",
|
||||
"next-redux-wrapper": "^1.0.0",
|
||||
"next-redux-wrapper": "^2.0.0-beta.6",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-redux": "^5.0.1",
|
||||
"redux": "^3.6.0",
|
||||
"redux": "^4.0.0",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-observable": "^0.17.0",
|
||||
"redux-thunk": "^2.1.0",
|
||||
"rxjs": "^5.5.2",
|
||||
"superagent": "^3.8.1",
|
||||
"universal-rx-request": "^1.0.3"
|
||||
"redux-observable": "^1.0.0",
|
||||
"rxjs": "^6.2.1",
|
||||
"universal-rxjs-ajax": "^2.0.0"
|
||||
},
|
||||
"license": "ISC"
|
||||
}
|
||||
|
|
28
examples/with-redux-observable/pages/_app.js
Normal file
28
examples/with-redux-observable/pages/_app.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import React from 'react'
|
||||
import { Provider } from 'react-redux'
|
||||
import App, { Container } from 'next/app'
|
||||
import withRedux from 'next-redux-wrapper'
|
||||
import makeStore from '../redux'
|
||||
|
||||
class MyApp extends App {
|
||||
static async getInitialProps ({ Component, ctx }) {
|
||||
const pageProps = Component.getInitialProps
|
||||
? await Component.getInitialProps(ctx)
|
||||
: {}
|
||||
|
||||
return { pageProps }
|
||||
}
|
||||
|
||||
render () {
|
||||
const { Component, pageProps, store } = this.props
|
||||
return (
|
||||
<Container>
|
||||
<Provider store={store}>
|
||||
<Component {...pageProps} />
|
||||
</Provider>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withRedux(makeStore)(MyApp)
|
|
@ -1,17 +1,18 @@
|
|||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
import withRedux from 'next-redux-wrapper'
|
||||
import initStore from '../redux'
|
||||
import { of, Subject } from 'rxjs'
|
||||
import { StateObservable } from 'redux-observable'
|
||||
import { connect } from 'react-redux'
|
||||
import CharacterInfo from '../components/CharacterInfo'
|
||||
import { rootEpic } from '../redux/epics'
|
||||
import * as actions from '../redux/actions'
|
||||
import { of } from 'rxjs/observable/of'
|
||||
|
||||
class Counter extends React.Component {
|
||||
static async getInitialProps ({ store, isServer }) {
|
||||
const state$ = new StateObservable(new Subject(), store.getState())
|
||||
const resultAction = await rootEpic(
|
||||
of(actions.fetchCharacter(isServer)),
|
||||
store
|
||||
state$
|
||||
).toPromise() // we need to convert Observable to Promise
|
||||
store.dispatch(resultAction)
|
||||
|
||||
|
@ -40,8 +41,7 @@ class Counter extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default withRedux(
|
||||
initStore,
|
||||
export default connect(
|
||||
null,
|
||||
{
|
||||
startFetchingCharacters: actions.startFetchingCharacters,
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import { interval } from 'rxjs/observable/interval'
|
||||
import { of } from 'rxjs/observable/of'
|
||||
import { interval, of } from 'rxjs'
|
||||
import { takeUntil, mergeMap, catchError, map } from 'rxjs/operators'
|
||||
import { combineEpics, ofType } from 'redux-observable'
|
||||
import ajax from 'universal-rx-request' // because standard AjaxObservable only works in browser
|
||||
import { request } from 'universal-rxjs-ajax' // because standard AjaxObservable only works in browser
|
||||
|
||||
import * as actions from './actions'
|
||||
import * as types from './actionTypes'
|
||||
|
||||
export const fetchUserEpic = (action$, store) =>
|
||||
export const fetchUserEpic = (action$, state$) =>
|
||||
action$.pipe(
|
||||
ofType(types.START_FETCHING_CHARACTERS),
|
||||
mergeMap(action => {
|
||||
return interval(3000).pipe(
|
||||
mergeMap(x =>
|
||||
map(x =>
|
||||
actions.fetchCharacter({
|
||||
isServer: store.getState().isServer
|
||||
isServer: state$.value.isServer
|
||||
})
|
||||
),
|
||||
takeUntil(action$.ofType(types.STOP_FETCHING_CHARACTERS))
|
||||
|
@ -22,24 +21,24 @@ export const fetchUserEpic = (action$, store) =>
|
|||
})
|
||||
)
|
||||
|
||||
export const fetchCharacterEpic = (action$, store) =>
|
||||
export const fetchCharacterEpic = (action$, state$) =>
|
||||
action$.pipe(
|
||||
ofType(types.FETCH_CHARACTER),
|
||||
mergeMap(action =>
|
||||
ajax({
|
||||
url: `https://swapi.co/api/people/${store.getState().nextCharacterId}`
|
||||
request({
|
||||
url: `https://swapi.co/api/people/${state$.value.nextCharacterId}`
|
||||
}).pipe(
|
||||
map(response =>
|
||||
actions.fetchCharacterSuccess(
|
||||
response.body,
|
||||
store.getState().isServer
|
||||
response.response,
|
||||
state$.value.isServer
|
||||
)
|
||||
),
|
||||
catchError(error =>
|
||||
of(
|
||||
actions.fetchCharacterFailure(
|
||||
error.response.body,
|
||||
store.getState().isServer
|
||||
error.xhr.response,
|
||||
state$.value.isServer
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import { createStore, applyMiddleware } from 'redux'
|
||||
import thunkMiddleware from 'redux-thunk'
|
||||
import { createLogger } from 'redux-logger'
|
||||
import { createEpicMiddleware } from 'redux-observable'
|
||||
import reducer from './reducer'
|
||||
import { rootEpic } from './epics'
|
||||
|
||||
export default function initStore (initialState) {
|
||||
const epicMiddleware = createEpicMiddleware(rootEpic)
|
||||
const epicMiddleware = createEpicMiddleware()
|
||||
const logger = createLogger({ collapsed: true }) // log every action to see what's happening behind the scenes.
|
||||
const reduxMiddleware = applyMiddleware(thunkMiddleware, epicMiddleware, logger)
|
||||
const reduxMiddleware = applyMiddleware(epicMiddleware, logger)
|
||||
|
||||
return createStore(reducer, initialState, reduxMiddleware)
|
||||
const store = createStore(reducer, initialState, reduxMiddleware)
|
||||
epicMiddleware.run(rootEpic)
|
||||
|
||||
return store
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue