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.
|
`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
|
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
|
```js
|
||||||
static async getInitialProps({ store, isServer }) {
|
static async getInitialProps({ store, isServer }) {
|
||||||
|
const state$ = new StateObservable(new Subject(), store.getState());
|
||||||
const resultAction = await rootEpic(
|
const resultAction = await rootEpic(
|
||||||
of(actions.fetchCharacter(isServer)),
|
of(actions.fetchCharacter(isServer)),
|
||||||
store
|
state$
|
||||||
).toPromise(); // we need to convert Observable to Promise
|
).toPromise(); // we need to convert Observable to Promise
|
||||||
store.dispatch(resultAction)};
|
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
|
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
|
v5.5.6, it will not work on both the server- and client-side. Instead we call
|
||||||
the default export from
|
the default export from
|
||||||
[universal-rx-request](https://www.npmjs.com/package/universal-rx-request) (as
|
[universal-rxjs-ajax](https://www.npmjs.com/package/universal-rxjs-ajax) (as
|
||||||
`ajax`).
|
`request`).
|
||||||
|
|
||||||
We transform the Observable we get from `ajax` into a Promise in order to await
|
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
|
its resolution. That resolution should be a action (since the epic returns
|
||||||
|
|
|
@ -9,17 +9,15 @@
|
||||||
"author": "tomaszmularczyk(tomasz.mularczyk89@gmail.com)",
|
"author": "tomaszmularczyk(tomasz.mularczyk89@gmail.com)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "latest",
|
"next": "latest",
|
||||||
"next-redux-wrapper": "^1.0.0",
|
"next-redux-wrapper": "^2.0.0-beta.6",
|
||||||
"react": "^16.0.0",
|
"react": "^16.0.0",
|
||||||
"react-dom": "^16.0.0",
|
"react-dom": "^16.0.0",
|
||||||
"react-redux": "^5.0.1",
|
"react-redux": "^5.0.1",
|
||||||
"redux": "^3.6.0",
|
"redux": "^4.0.0",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-observable": "^0.17.0",
|
"redux-observable": "^1.0.0",
|
||||||
"redux-thunk": "^2.1.0",
|
"rxjs": "^6.2.1",
|
||||||
"rxjs": "^5.5.2",
|
"universal-rxjs-ajax": "^2.0.0"
|
||||||
"superagent": "^3.8.1",
|
|
||||||
"universal-rx-request": "^1.0.3"
|
|
||||||
},
|
},
|
||||||
"license": "ISC"
|
"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 React from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import withRedux from 'next-redux-wrapper'
|
import { of, Subject } from 'rxjs'
|
||||||
import initStore from '../redux'
|
import { StateObservable } from 'redux-observable'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
import CharacterInfo from '../components/CharacterInfo'
|
import CharacterInfo from '../components/CharacterInfo'
|
||||||
import { rootEpic } from '../redux/epics'
|
import { rootEpic } from '../redux/epics'
|
||||||
import * as actions from '../redux/actions'
|
import * as actions from '../redux/actions'
|
||||||
import { of } from 'rxjs/observable/of'
|
|
||||||
|
|
||||||
class Counter extends React.Component {
|
class Counter extends React.Component {
|
||||||
static async getInitialProps ({ store, isServer }) {
|
static async getInitialProps ({ store, isServer }) {
|
||||||
|
const state$ = new StateObservable(new Subject(), store.getState())
|
||||||
const resultAction = await rootEpic(
|
const resultAction = await rootEpic(
|
||||||
of(actions.fetchCharacter(isServer)),
|
of(actions.fetchCharacter(isServer)),
|
||||||
store
|
state$
|
||||||
).toPromise() // we need to convert Observable to Promise
|
).toPromise() // we need to convert Observable to Promise
|
||||||
store.dispatch(resultAction)
|
store.dispatch(resultAction)
|
||||||
|
|
||||||
|
@ -40,8 +41,7 @@ class Counter extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRedux(
|
export default connect(
|
||||||
initStore,
|
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
startFetchingCharacters: actions.startFetchingCharacters,
|
startFetchingCharacters: actions.startFetchingCharacters,
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
import { interval } from 'rxjs/observable/interval'
|
import { interval, of } from 'rxjs'
|
||||||
import { of } from 'rxjs/observable/of'
|
|
||||||
import { takeUntil, mergeMap, catchError, map } from 'rxjs/operators'
|
import { takeUntil, mergeMap, catchError, map } from 'rxjs/operators'
|
||||||
import { combineEpics, ofType } from 'redux-observable'
|
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 actions from './actions'
|
||||||
import * as types from './actionTypes'
|
import * as types from './actionTypes'
|
||||||
|
|
||||||
export const fetchUserEpic = (action$, store) =>
|
export const fetchUserEpic = (action$, state$) =>
|
||||||
action$.pipe(
|
action$.pipe(
|
||||||
ofType(types.START_FETCHING_CHARACTERS),
|
ofType(types.START_FETCHING_CHARACTERS),
|
||||||
mergeMap(action => {
|
mergeMap(action => {
|
||||||
return interval(3000).pipe(
|
return interval(3000).pipe(
|
||||||
mergeMap(x =>
|
map(x =>
|
||||||
actions.fetchCharacter({
|
actions.fetchCharacter({
|
||||||
isServer: store.getState().isServer
|
isServer: state$.value.isServer
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
takeUntil(action$.ofType(types.STOP_FETCHING_CHARACTERS))
|
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(
|
action$.pipe(
|
||||||
ofType(types.FETCH_CHARACTER),
|
ofType(types.FETCH_CHARACTER),
|
||||||
mergeMap(action =>
|
mergeMap(action =>
|
||||||
ajax({
|
request({
|
||||||
url: `https://swapi.co/api/people/${store.getState().nextCharacterId}`
|
url: `https://swapi.co/api/people/${state$.value.nextCharacterId}`
|
||||||
}).pipe(
|
}).pipe(
|
||||||
map(response =>
|
map(response =>
|
||||||
actions.fetchCharacterSuccess(
|
actions.fetchCharacterSuccess(
|
||||||
response.body,
|
response.response,
|
||||||
store.getState().isServer
|
state$.value.isServer
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
catchError(error =>
|
catchError(error =>
|
||||||
of(
|
of(
|
||||||
actions.fetchCharacterFailure(
|
actions.fetchCharacterFailure(
|
||||||
error.response.body,
|
error.xhr.response,
|
||||||
store.getState().isServer
|
state$.value.isServer
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import { createStore, applyMiddleware } from 'redux'
|
import { createStore, applyMiddleware } from 'redux'
|
||||||
import thunkMiddleware from 'redux-thunk'
|
|
||||||
import { createLogger } from 'redux-logger'
|
import { createLogger } from 'redux-logger'
|
||||||
import { createEpicMiddleware } from 'redux-observable'
|
import { createEpicMiddleware } from 'redux-observable'
|
||||||
import reducer from './reducer'
|
import reducer from './reducer'
|
||||||
import { rootEpic } from './epics'
|
import { rootEpic } from './epics'
|
||||||
|
|
||||||
export default function initStore (initialState) {
|
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 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