1
0
Fork 0
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:
Tomek 2018-07-22 01:37:59 +02:00 committed by Tim Neutkens
parent 822cc3c863
commit 53853d3fa9
6 changed files with 62 additions and 34 deletions

View file

@ -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

View file

@ -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"
}

View 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)

View file

@ -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,

View file

@ -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
)
)
)

View file

@ -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
};