Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component / Route based async Server-Side Rendering #93

Closed
chris-metz opened this issue Dec 22, 2016 · 10 comments · Fixed by #1621
Closed

Component / Route based async Server-Side Rendering #93

chris-metz opened this issue Dec 22, 2016 · 10 comments · Fixed by #1621

Comments

@chris-metz
Copy link

First, thanks for this project!

I'd like to make an async fetch of data for the redux store, but only for a specific route / component that gets rendered server side. From the docs of 'redux-router-engine' I got this working:

export default function createReduxStore(req) {
  const store = configureStore();

  return Promise.all([
    store.dispatch(yourAction())
    // dispatch any other asynchronous actions here
  ])
  .then(() => store);
}

But with this the 'yourAction' gets dispatched for every route. Is there a way / best-practice to do this only for specific routes / components?

Tank you!

@chris-metz chris-metz changed the title Component based async Server-Side Rendering Component / Route based async Server-Side Rendering Dec 22, 2016
@sbuys
Copy link

sbuys commented Dec 28, 2016

+1. Thanks for open sourcing this work! 🙏. Adding to @Chris-mE, it would be nice to have a more fleshed out "real world" SSR example. Initially I thought Electrode Redux Router Engine would help bootstrap initial state based on current route.

Does something like redux-taxi or redux-connect make sense? It would be nice if Electrode provided a module for this or indicated best practices.

@jchip
Copy link
Member

jchip commented Jan 10, 2017

Hi, thanks for reporting this. At the moment initializing redux store according to route in the router engine is not well defined so it's up the to user on how to do that.

@LeeFrancis
Copy link

LeeFrancis commented Jan 10, 2017

I found myself checking the current path at render. Not sure if this is the best approach but my code looks something like this.

function createReduxStore(req, match) {
  const initialState = {
  }; // Fill this with my initial state - confippet config val's etc.
  const store = configureStore(initialState);
  const { location } = match.renderProps;
  const actions = location.pathname === "/pathToMatch" ? [
    store.dispatch(yourAction())
  ] :
  [];
  return Promise.all(actions).then(() => store);
}

@sbuys
Copy link

sbuys commented Jan 11, 2017

@LeeFrancis Yeah that's the general approach I believe, though something like redux-connect, redux-taxi, or react-jobs seems like the way to go in terms of declaring the data requirements at the Component level. I'm leaning towards react-jobs because the work @ctrlplusb is doing in react-universally is pretty rad and he's active in moving with best practices.

@jchip Thanks for the note. Keeping an eye on how this progresses. IMO the boilerplate is incomplete if it doesn't close the loop on the full server-side data flow and offer at least a recommended approach to the problem. My initial read of the electrode site led me to believe there was a module for this.

@TheDartCode
Copy link

@sbuys Thanks for the recommendation for these packages. I really liked the way redux-taxi works.
However, redux-taxi and redux-connect need to be inserted as middleware and also under the Provider component, making it incompatible with the way the current version of ReduxRouterEngine works.
Am I right? or am I missing something?

@TheDartCode
Copy link

@Chris-mE and whoever else is looking for a way to deal with this, I came up with a way to have declarative route-based redux store initializers, that also support async actions (and pre-fetching) for SSR.
I have set up a sample app here
Feel free to open an issue and discuss anything you wish.
@jchip it would be cool if you could give your feedback, too!

@jchip
Copy link
Member

jchip commented Jul 6, 2017

You can specify an init for each route to supply a custom callback for initializing the redux store now. https://electrode.gitbooks.io/electrode/content/chapter1/advanced/stand-alone-modules/redux-router-engine.html#init-attribute

@jchip jchip closed this as completed Jul 6, 2017
@hugotox
Copy link

hugotox commented Aug 29, 2017

hey @jchip thanks for the link but I could not find any example how to use the route init. What's inside that kind of handler?

@hugotox
Copy link

hugotox commented Aug 29, 2017

Anyways since I could not find a working example I came up with this approach:

  1. Define a static method on the component:
class MyComponent extends Component {
  static fetchData() {
    return actions.fetchData() // assuming thunk is there and fetchData returns an async call
  }
  // ... component stuff
}
  1. On the server loop the matched components, and if they have fetchData defined, add it to an array of promises and dispatch them using your store
function createReduxStore(req, match) { // eslint-disable-line
  const initialState = {};
  const store = createStore(
    rootReducer,
    initialState,
    applyMiddleware(thunk)
  );
  const renderProps = match.renderProps
  const dataFetchers = []
  renderProps.routes.map(route => {
    if (route.component && route.component.fetchData) {
      dataFetchers.push(
        store.dispatch(
          route.component.fetchData(renderProps.params, renderProps.location.query)
        )
      )
    }
  })
  return Promise.all(dataFetchers).then(() => {
    return store;
  });
}

This will fetch data server side only for the current route

@TheDartCode
Copy link

@hugotox Check my story at https://medium.com/@thedartcode/electrode-io-adventures-part-1-route-based-store-initialization-348f9c640843 I explain there both the solution proposed by the Electrode team as well as my take on the subject.

I did something "custom" like you, only instead of adding fetchData to the components, I extended the routes with it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants