gabrielbull / react-router-server

Server Side Rendering library for React Router v4.
MIT License
434 stars 17 forks source link

Redux support needed #15

Open BerndWessels opened 7 years ago

BerndWessels commented 7 years ago

Hi this is awesome project, but it definitely needs redux support. Is this on the road-map?

gabrielbull commented 7 years ago

Do you have an example of how would you envision this to work?

BerndWessels commented 7 years ago

Maybe something like this:

import {Provider} from 'preact-redux';
import {applyMiddleware, createStore} from 'redux';
import { renderToString } from 'react-router-server';
...

let store = createStore(
      rootReducer,
      applyMiddleware(epicMiddleware)
    );

renderToString(<Provider store={store}><App/></Provider>)
  .then(({ html, state }) => {
    // state here should actually be the redux-state at the end of all async operations.
  });

and just the normal redux connect within the components.

pdiniz13 commented 7 years ago

Would also be interested in knowing if this is in the works

gabrielbull commented 7 years ago

How would we know when all async operations are done in redux?

Wouldn't it currently work with redux by doing something like this:

import * as React from 'react';
import {fetchState} from 'react-router-server';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux'

@fetchState(
  state => state,
  actions => ({ done: actions.done })
)
@connect(
  ({ message }) => ({ message }),
  dispatch => ({ actions: bindActionCreators(actionCreators, dispatch) })
)
class Example extends React.PureComponent {
  componentWillMount() {
    this.props.actions.loadSomeMessage()
      .then((message) => this.props.done({ message }));
  }

 render() {
    return (
      <div>{this.props.message || 'Loading...'}</div>
    );
  }
}

export default Example;
pdiniz13 commented 7 years ago

what seems to be the most popular option is a double render on the server, the first one to create the state and the second to render the code.


    <Root store={store} history={history} />
  );

  // send signal to sagas that we're done
  store.dispatch(END);

  // wait for all tasks to finish
  await sagasDone();

  // capture the state after the first render
  const state = store.getState().toJS();
  const appState = `window.APP_STATE = ${htmlescape(state)}`;

  // 2nd render phase - the sagas triggered in the first phase are resolved by now
  const body = renderToString(
    <Root store={store} history={history} />
  );```
oyeanuj commented 7 years ago

@gabrielbull Could you clarify usage with Redux - use your comment above or the README 'with Redux` section?