Best async serverside loading technique? #99

Closed
erikras opened this Issue Jun 15, 2015 · 63 comments

Comments

@erikras
Contributor

erikras commented Jun 15, 2015

First of all, I love this library and the patterns you guys are using. 馃憤馃憤

I'm trying to use redux to build an isomorphic app. It's working beautifully so far, except that I need to figure out how to wait until my stores have loaded (on the server) before returning the initial page load. Ideally, the loading should take place in the stores themselves, but when I call dispatch(userActions.load()), the store has to return the new state (i.e. return { ...state, loading: true };), so it can't return a promise to wait for. dispatch() returns the action passed to it for some reason. I'd really like something like...

dispatch(someAsyncAction, successAction, failureAction) => Promise

...where the promise doesn't resolve until one of the other two actions is dispatched.

Is that the sort of thing that could be enabled with the middleware pattern?

Am I totally off base and there's a simple way to do this already?

Thanks.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 15, 2015

Collaborator

Hey, thanks!

Ideally, the loading should take place in the stores themselves

Redux enforces that Stores are completely synchronous. What you describe should happen in the action creator instead.

I think it may even be possible with the default thunk middleware. Your action creator would look like:

export function doSomethingAsync() {
  return (dispatch) => {
    dispatch({ type: SOMETHING_STARTED });

    return requestSomething().then(
      (result) =>  dispatch({ type: SOMETHING_COMPLETED, result }),
      (error) =>  dispatch({ type: SOMETHING_FAILED, error })
    );
  };
}

and handling the actual (granular) actions in the Store.

It's also possible to write a custom middleware to remove the boilerplate.

Collaborator

gaearon commented Jun 15, 2015

Hey, thanks!

Ideally, the loading should take place in the stores themselves

Redux enforces that Stores are completely synchronous. What you describe should happen in the action creator instead.

I think it may even be possible with the default thunk middleware. Your action creator would look like:

export function doSomethingAsync() {
  return (dispatch) => {
    dispatch({ type: SOMETHING_STARTED });

    return requestSomething().then(
      (result) =>  dispatch({ type: SOMETHING_COMPLETED, result }),
      (error) =>  dispatch({ type: SOMETHING_FAILED, error })
    );
  };
}

and handling the actual (granular) actions in the Store.

It's also possible to write a custom middleware to remove the boilerplate.

@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 15, 2015

Contributor

Genius! I figured I was overlooking something obvious. I like that separation of doing and storing.

I look forward to watching this library grow, although it's pretty doggone complete already. Cheers, @gaearon!

Contributor

erikras commented Jun 15, 2015

Genius! I figured I was overlooking something obvious. I like that separation of doing and storing.

I look forward to watching this library grow, although it's pretty doggone complete already. Cheers, @gaearon!

@erikras erikras closed this Jun 15, 2015

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 15, 2015

Collaborator

You can also write a custom middleware like this

export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    next({ ...rest, readyState: 'request' );
    return promise.then(
      (result) => next({ ...rest, result, readyState: 'success' }),
      (error) => next({ ...rest, error, readyState: 'failure' })
    );
  };
}

and use it instead of the default one.

This will let you write async action creators like

function doSomethingAsync(userId) {
  return {
    type: SOMETHING,
    promise: requestSomething(userId),
    userId
  };
}

and have them turn into

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, readyState: 'success' }
{ type: SOMETHING, userId: 2, readyState: 'failure' }
Collaborator

gaearon commented Jun 15, 2015

You can also write a custom middleware like this

export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    next({ ...rest, readyState: 'request' );
    return promise.then(
      (result) => next({ ...rest, result, readyState: 'success' }),
      (error) => next({ ...rest, error, readyState: 'failure' })
    );
  };
}

and use it instead of the default one.

This will let you write async action creators like

function doSomethingAsync(userId) {
  return {
    type: SOMETHING,
    promise: requestSomething(userId),
    userId
  };
}

and have them turn into

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, readyState: 'success' }
{ type: SOMETHING, userId: 2, readyState: 'failure' }
@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 15, 2015

Contributor

Ooh, that's nice as well, and more of what I had in mind when I asked the original question. I can't tell if I like the tradeoff in reducing the number of action constants in exchange for adding ifs to check the readyState inside the store. I think I might prefer having addtional _SUCCESS and _FAILURE versions of each action just to avoid putting an if inside a case.

Thanks, though.

Contributor

erikras commented Jun 15, 2015

Ooh, that's nice as well, and more of what I had in mind when I asked the original question. I can't tell if I like the tradeoff in reducing the number of action constants in exchange for adding ifs to check the readyState inside the store. I think I might prefer having addtional _SUCCESS and _FAILURE versions of each action just to avoid putting an if inside a case.

Thanks, though.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 15, 2015

Collaborator

Yeah that's totally up to your taste. You could have a similar version that turns types: { request: ..., success: ..., failure: ... } into actions. This is the point of making it a middleware instead of baking into the library: everybody has their own taste to these things.

Collaborator

gaearon commented Jun 15, 2015

Yeah that's totally up to your taste. You could have a similar version that turns types: { request: ..., success: ..., failure: ... } into actions. This is the point of making it a middleware instead of baking into the library: everybody has their own taste to these things.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 15, 2015

Collaborator
// Middleware
export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, types, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    const [REQUEST, SUCCESS, FAILURE] = types;
    next({ ...rest, type: REQUEST });
    return promise.then(
      (result) => next({ ...rest, result, type: SUCCESS }),
      (error) => next({ ...rest, error, type: FAILURE })
    );
  };
}

// Usage
function doSomethingAsync(userId) {
  return {
    types: [SOMETHING_REQUEST, SOMETHING_SUCCESS, SOMETHING_FAILURE],
    promise: requestSomething(userId),
    userId
  };
}
Collaborator

gaearon commented Jun 15, 2015

// Middleware
export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, types, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    const [REQUEST, SUCCESS, FAILURE] = types;
    next({ ...rest, type: REQUEST });
    return promise.then(
      (result) => next({ ...rest, result, type: SUCCESS }),
      (error) => next({ ...rest, error, type: FAILURE })
    );
  };
}

// Usage
function doSomethingAsync(userId) {
  return {
    types: [SOMETHING_REQUEST, SOMETHING_SUCCESS, SOMETHING_FAILURE],
    promise: requestSomething(userId),
    userId
  };
}
@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 15, 2015

Contributor

Oh man, I love that solution. So much nicer than having the then() and additional calls to dispatch() like the first solution you proposed. Hooray for middleware!

Contributor

erikras commented Jun 15, 2015

Oh man, I love that solution. So much nicer than having the then() and additional calls to dispatch() like the first solution you proposed. Hooray for middleware!

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 15, 2015

Collaborator

Let me know how (and whether ;-) it works!
We have not really tested custom middleware much.

Collaborator

gaearon commented Jun 15, 2015

Let me know how (and whether ;-) it works!
We have not really tested custom middleware much.

@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 15, 2015

Contributor

You left out a } (that's -1 point 馃榾), but it worked like a charm! First time.

Contributor

erikras commented Jun 15, 2015

You left out a } (that's -1 point 馃榾), but it worked like a charm! First time.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 15, 2015

Collaborator

馃憤

Collaborator

gaearon commented Jun 15, 2015

馃憤

@iest

This comment has been minimized.

Show comment
Hide comment
@iest

iest Jun 17, 2015

@erikras I'm curios how you implemented waiting for the promises to resolve on the server?

iest commented Jun 17, 2015

@erikras I'm curios how you implemented waiting for the promises to resolve on the server?

@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 17, 2015

Contributor

This is just pseudocode, so don't go pasting this anywhere, but I'm using react-router (whose api is changing as fast as redux's) something like this:

app.get('/my-app', (req, res) => {
  Router.run(routes, req.path, (error, initialState) => {
    Promise.all(initialState.components
      .filter(component => component.fetchData) // only components with a static fetchData()
      .map(component => {
        // have each component dispatch load actions that return promises
        return component.fetchData(redux.dispatch);
      })) // Promise.all combines all the promises into one
      .then(() => {
        // now fetchData() has been run on every component in my route, and the
        // promises resolved, so we know the redux state is populated
        res.send(generatePage(redux));
      });
  });
});

Does that clear anything up?

Contributor

erikras commented Jun 17, 2015

This is just pseudocode, so don't go pasting this anywhere, but I'm using react-router (whose api is changing as fast as redux's) something like this:

app.get('/my-app', (req, res) => {
  Router.run(routes, req.path, (error, initialState) => {
    Promise.all(initialState.components
      .filter(component => component.fetchData) // only components with a static fetchData()
      .map(component => {
        // have each component dispatch load actions that return promises
        return component.fetchData(redux.dispatch);
      })) // Promise.all combines all the promises into one
      .then(() => {
        // now fetchData() has been run on every component in my route, and the
        // promises resolved, so we know the redux state is populated
        res.send(generatePage(redux));
      });
  });
});

Does that clear anything up?

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 17, 2015

Collaborator

@iest

Quoting your problem in Slack:

I鈥檝e got a route handler with

 static async routerWillRun({dispatch}) {
   return await dispatch(UserActions.fooBar());
 }

where UserActions.fooBar() is:

export function fooBar() {
 return dispatch => {
   doAsync().then(() => dispatch({type: FOO_BAR}));
 };
}

then in the server render I鈥檓 yielding:

 yield myHandler.routerWillRun({dispatch: redux.dispatch});

but it doesn鈥檛 work.

I think the problem here is you're not actually returning anything from fooBar's nested method.

Either remove the braces:

export function fooBar() {
  return dispatch =>
    doAsync().then(() => dispatch({type: FOO_BAR}));
}

or add an explicit return statement:

export function fooBar() {
  return dispatch => {
    return doAsync().then(() => dispatch({type: FOO_BAR}));
  };
}

Either way, it might be easier to use a custom promise middleware as suggested above.

Collaborator

gaearon commented Jun 17, 2015

@iest

Quoting your problem in Slack:

I鈥檝e got a route handler with

 static async routerWillRun({dispatch}) {
   return await dispatch(UserActions.fooBar());
 }

where UserActions.fooBar() is:

export function fooBar() {
 return dispatch => {
   doAsync().then(() => dispatch({type: FOO_BAR}));
 };
}

then in the server render I鈥檓 yielding:

 yield myHandler.routerWillRun({dispatch: redux.dispatch});

but it doesn鈥檛 work.

I think the problem here is you're not actually returning anything from fooBar's nested method.

Either remove the braces:

export function fooBar() {
  return dispatch =>
    doAsync().then(() => dispatch({type: FOO_BAR}));
}

or add an explicit return statement:

export function fooBar() {
  return dispatch => {
    return doAsync().then(() => dispatch({type: FOO_BAR}));
  };
}

Either way, it might be easier to use a custom promise middleware as suggested above.

@mattybow

This comment has been minimized.

Show comment
Hide comment
@mattybow

mattybow Jun 17, 2015

Contributor

@erikras Regarding your last comment where you are calling the fetchData method on what you have as initialState.components (in the callback of Router.run), the object you get the component references from only return the route handlers matched. What are your thoughts on reaching components that might not be a matched route handler, i.e a child component, but needs to fetch data?

here's an example of what I'm talking about

import React from 'react';
import Router from 'react-router';
import {Route, RouteHandler, DefaultRoute} from 'react-router';

//imagine Bar needs some data
const Bar = React.createClass({
  render(){
    return(
      <div>bar</div>);
  }
});

const Foo = React.createClass({
  render(){
    return (
      <div>
        foo
        <Bar/>
      </div>);
  }
});


const App = React.createClass({
  render(){
    return (
      <div>
        <RouteHandler />
      </div>
    );
  }
});

const routes = (
  <Route path="/" handler={App} name="App">
    <DefaultRoute handler={Foo} name="Foo"/>
  </Route>
);

Router.run(routes,'/',function(Root,state){
  console.log(state);
});

output:

{ path: '/',
  action: null,
  pathname: '/',
  routes: 
   [ { name: 'App',
       path: '/',
       paramNames: [],
       ignoreScrollBehavior: false,
       isDefault: false,
       isNotFound: false,
       onEnter: undefined,
       onLeave: undefined,
       handler: [Object],
       defaultRoute: [Object],
       childRoutes: [Object] },
     { name: 'Foo',
       path: '/',
       paramNames: [],
       ignoreScrollBehavior: false,
       isDefault: true,
       isNotFound: false,
       onEnter: undefined,
       onLeave: undefined,
       handler: [Object] } ],
  params: {},
  query: {} }

You won't have access to Bar in Routes

Contributor

mattybow commented Jun 17, 2015

@erikras Regarding your last comment where you are calling the fetchData method on what you have as initialState.components (in the callback of Router.run), the object you get the component references from only return the route handlers matched. What are your thoughts on reaching components that might not be a matched route handler, i.e a child component, but needs to fetch data?

here's an example of what I'm talking about

import React from 'react';
import Router from 'react-router';
import {Route, RouteHandler, DefaultRoute} from 'react-router';

//imagine Bar needs some data
const Bar = React.createClass({
  render(){
    return(
      <div>bar</div>);
  }
});

const Foo = React.createClass({
  render(){
    return (
      <div>
        foo
        <Bar/>
      </div>);
  }
});


const App = React.createClass({
  render(){
    return (
      <div>
        <RouteHandler />
      </div>
    );
  }
});

const routes = (
  <Route path="/" handler={App} name="App">
    <DefaultRoute handler={Foo} name="Foo"/>
  </Route>
);

Router.run(routes,'/',function(Root,state){
  console.log(state);
});

output:

{ path: '/',
  action: null,
  pathname: '/',
  routes: 
   [ { name: 'App',
       path: '/',
       paramNames: [],
       ignoreScrollBehavior: false,
       isDefault: false,
       isNotFound: false,
       onEnter: undefined,
       onLeave: undefined,
       handler: [Object],
       defaultRoute: [Object],
       childRoutes: [Object] },
     { name: 'Foo',
       path: '/',
       paramNames: [],
       ignoreScrollBehavior: false,
       isDefault: true,
       isNotFound: false,
       onEnter: undefined,
       onLeave: undefined,
       handler: [Object] } ],
  params: {},
  query: {} }

You won't have access to Bar in Routes

@iest

This comment has been minimized.

Show comment
Hide comment
@iest

iest Jun 18, 2015

@erikras Fantastic! That's exactly the kind of route I want to go down. Thanks for sharing.

iest commented Jun 18, 2015

@erikras Fantastic! That's exactly the kind of route I want to go down. Thanks for sharing.

@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 18, 2015

Contributor

@iest I hope that pun was intentional, "go down a route" by iterating through the matching routes. :-)

@mattybow That is true. If you really need a component that is not in your routes to load something, then the only option is to run React.renderToString() once (discarding the result), do all your loading in componentWillMount(), and somehow save the promises as you go. This is what I was doing with my own homegrown routing solution before react-router supported server side rendering. I would suggest that needing non-route components to do loading might be a symptom of a design problem. In most use cases a route knows what data its components will need.

Contributor

erikras commented Jun 18, 2015

@iest I hope that pun was intentional, "go down a route" by iterating through the matching routes. :-)

@mattybow That is true. If you really need a component that is not in your routes to load something, then the only option is to run React.renderToString() once (discarding the result), do all your loading in componentWillMount(), and somehow save the promises as you go. This is what I was doing with my own homegrown routing solution before react-router supported server side rendering. I would suggest that needing non-route components to do loading might be a symptom of a design problem. In most use cases a route knows what data its components will need.

@transedward

This comment has been minimized.

Show comment
Hide comment
@transedward

transedward Jun 19, 2015

@erikras
do you have any public repo to see a whole example on you solution there?

@erikras
do you have any public repo to see a whole example on you solution there?

@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 19, 2015

Contributor

@transedward I wish I did, but my stuff so far using the method I detailed here is still very immature. Sorry.

Contributor

erikras commented Jun 19, 2015

@transedward I wish I did, but my stuff so far using the method I detailed here is still very immature. Sorry.

@trueter

This comment has been minimized.

Show comment
Hide comment
@trueter

trueter Jun 23, 2015

+1 on the advanced isomorphic example
I love where this is going!

trueter commented Jun 23, 2015

+1 on the advanced isomorphic example
I love where this is going!

@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 23, 2015

Contributor

@transedward Here's a sample project with all the bleeding edge tech I've cobbled together. https://github.com/erikras/react-redux-universal-hot-example/

Contributor

erikras commented Jun 23, 2015

@transedward Here's a sample project with all the bleeding edge tech I've cobbled together. https://github.com/erikras/react-redux-universal-hot-example/

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 23, 2015

Collaborator

@erikras This is awesome! Can you please submit PR to add it to this README and React Hot Loader's docs' "starter kits" section?

Collaborator

gaearon commented Jun 23, 2015

@erikras This is awesome! Can you please submit PR to add it to this README and React Hot Loader's docs' "starter kits" section?

@erikras

This comment has been minimized.

Show comment
Hide comment
@erikras

erikras Jun 23, 2015

Contributor

Thanks! PRs submitted.

Contributor

erikras commented Jun 23, 2015

Thanks! PRs submitted.

@trueter

This comment has been minimized.

Show comment
Hide comment
@trueter

trueter Jun 23, 2015

@erikras Great - Thank you!

trueter commented Jun 23, 2015

@erikras Great - Thank you!

@pburtchaell

This comment has been minimized.

Show comment
Hide comment
@pburtchaell

pburtchaell Jul 13, 2015

Just a note that鈥攂ased off some of the ides in this conversation鈥擨 made a middleware to handle promises: https://github.com/pburtchaell/redux-promise-middleware.

Just a note that鈥攂ased off some of the ides in this conversation鈥擨 made a middleware to handle promises: https://github.com/pburtchaell/redux-promise-middleware.

@taylorhakes

This comment has been minimized.

Show comment
Hide comment
Contributor

taylorhakes commented Jul 13, 2015

@bananaoomarang bananaoomarang referenced this issue in bananaoomarang/isomorphic-redux Jul 14, 2015

Closed

async actions #2

@wmertens

This comment has been minimized.

Show comment
Hide comment
@wmertens

wmertens Jul 28, 2015

Contributor

Two thoughts on this:

  1. Promises that get converted to actions could be passed along with the action and put in the Redux Store.

    Then, to know if your page is ready to render, simply check if all promises have completed. Perhaps use a middleware that chains all passing promises together and provides a promise for when there are no pending promises.

  2. How about letting selectors call actions for missing data?

    Suppose you want to render message 3, then your message container will render <Message id={3}> and the message selector will check if state.msgs[3] exists and if not, dispatch a message loading promise.

So combine the two and the components would autoselect their needed data and you'd know when they are done.

Contributor

wmertens commented Jul 28, 2015

Two thoughts on this:

  1. Promises that get converted to actions could be passed along with the action and put in the Redux Store.

    Then, to know if your page is ready to render, simply check if all promises have completed. Perhaps use a middleware that chains all passing promises together and provides a promise for when there are no pending promises.

  2. How about letting selectors call actions for missing data?

    Suppose you want to render message 3, then your message container will render <Message id={3}> and the message selector will check if state.msgs[3] exists and if not, dispatch a message loading promise.

So combine the two and the components would autoselect their needed data and you'd know when they are done.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jul 28, 2015

Collaborator

I'm pretty sure about 鈥渄on鈥檛 put anything unserializable into store or actions鈥. It's one of the invariants that's been working really well for me (and allowed time travel, for example) and there need to be very compelling reasons to consider changing it.

Collaborator

gaearon commented Jul 28, 2015

I'm pretty sure about 鈥渄on鈥檛 put anything unserializable into store or actions鈥. It's one of the invariants that's been working really well for me (and allowed time travel, for example) and there need to be very compelling reasons to consider changing it.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jul 28, 2015

Collaborator

Then, to know if your page is ready to render, simply check if all promises have completed. Perhaps use a middleware that chains all passing promises together and provides a promise for when there are no pending promises.

This actually doesn't require to put promises in the store in the end, and I like this. The difference is that, at the end of the dispatch chain, raw actions don't contain any promises. Those are 鈥渃ollected鈥 by the said middleware instead.

Collaborator

gaearon commented Jul 28, 2015

Then, to know if your page is ready to render, simply check if all promises have completed. Perhaps use a middleware that chains all passing promises together and provides a promise for when there are no pending promises.

This actually doesn't require to put promises in the store in the end, and I like this. The difference is that, at the end of the dispatch chain, raw actions don't contain any promises. Those are 鈥渃ollected鈥 by the said middleware instead.

@wmertens

This comment has been minimized.

Show comment
Hide comment
@wmertens

wmertens Jul 28, 2015

Contributor

One thing I often do when working with promises is to keep a reference to a promise around so that when other requests for the same thing come in, I simply return that same promise, providing debouncing. I then delete the reference some time after the promise completed, providing configurable caching.

I really have to start using Redux in real apps, because I wonder what to do with those references in Redux. I kind of want to stick them into the store to make the actionCreator stateless (or at least making the state explicit). Passing the promise via an action is a nice way to export it, but then you'd need to get it back afterwards somehow. Hmmm.

Contributor

wmertens commented Jul 28, 2015

One thing I often do when working with promises is to keep a reference to a promise around so that when other requests for the same thing come in, I simply return that same promise, providing debouncing. I then delete the reference some time after the promise completed, providing configurable caching.

I really have to start using Redux in real apps, because I wonder what to do with those references in Redux. I kind of want to stick them into the store to make the actionCreator stateless (or at least making the state explicit). Passing the promise via an action is a nice way to export it, but then you'd need to get it back afterwards somehow. Hmmm.

@gre

This comment has been minimized.

Show comment
Hide comment
@gre

gre Jul 31, 2015

I'm really looking forward the answer to the last point of @wmertens .
Avoiding multiple concurrent calls (do nothing if something is pending) is a frequent use-case, not sure what is the best way to answer that (because you can't access the store's state from an actionCreator).

Should the actionCreator user (the component) check everytime in the state if he can or not dispatch the action? You have to do it everytime then.. Maybe you need to introduce your own @connect annotation that wrap this?

gre commented Jul 31, 2015

I'm really looking forward the answer to the last point of @wmertens .
Avoiding multiple concurrent calls (do nothing if something is pending) is a frequent use-case, not sure what is the best way to answer that (because you can't access the store's state from an actionCreator).

Should the actionCreator user (the component) check everytime in the state if he can or not dispatch the action? You have to do it everytime then.. Maybe you need to introduce your own @connect annotation that wrap this?

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jul 31, 2015

Collaborator

because you can't access the store's state from an actionCreator

Why? You can do it just fine if you use thunk middleware.

function doSomething() {
  return { type: 'SOMETHING' };
}

function maybeDoSomething() {
  return function (dispatch, getState) {
    if (getState().isFetching) {
      return;
    }

    dispatch(doSomething());
  };
}

store.dispatch(maybeDoSomething());
Collaborator

gaearon commented Jul 31, 2015

because you can't access the store's state from an actionCreator

Why? You can do it just fine if you use thunk middleware.

function doSomething() {
  return { type: 'SOMETHING' };
}

function maybeDoSomething() {
  return function (dispatch, getState) {
    if (getState().isFetching) {
      return;
    }

    dispatch(doSomething());
  };
}

store.dispatch(maybeDoSomething());
@gre

This comment has been minimized.

Show comment
Hide comment
@gre

gre Jul 31, 2015

that solves it!
I thought for a time (for no reason) that accessing the state in actionCreator was a bad practice^^ since the action creator caller can access the state, I don't see why the actionCreator should not, so yeah cool we can do this :)

Thanks @gaearon

gre commented Jul 31, 2015

that solves it!
I thought for a time (for no reason) that accessing the state in actionCreator was a bad practice^^ since the action creator caller can access the state, I don't see why the actionCreator should not, so yeah cool we can do this :)

Thanks @gaearon

@justin808

This comment has been minimized.

Show comment
Hide comment
@justin808

justin808 Aug 5, 2015

@gaearon , is this technique of using Thunk and distinct actions http://gaearon.github.io/redux/docs/api/applyMiddleware.html preferable to your answer above:

You can also write a custom middleware like this

export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    next({ ...rest, readyState: 'request' );
    return promise.then(
      (result) => next({ ...rest, result, readyState: 'success' }),
      (error) => next({ ...rest, error, readyState: 'failure' })
    );
  };
}

and use it instead of the default one.
This will let you write async action creators like

function doSomethingAsync(userId) {
  return {
    type: SOMETHING,
    promise: requestSomething(userId),
    userId
  };
}

and have them turn into

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, readyState: 'success' }
{ type: SOMETHING, userId: 2, readyState: 'failure' }

Also,

I think for the last part, you meant:

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, result, readyState: 'success' }
{ type: SOMETHING, userId: 2, error, readyState: 'failure' }

I'm guessing it just depends on whether one wants to create separate actions for the success or failure callbacks of the promise, rather than using the auto-generated one.

In your thunk example:

function makeASandwichWithSecretSauce(forPerson) {

  // Invert control!
  // Return a function that accepts `dispatch` so we can dispatch later.
  // Thunk middleware knows how to turn thunk async actions into actions.

  return function (dispatch) {
    return fetchSecretSauce().then(
      sauce => dispatch(makeASandwich(forPerson, sauce)),
      error => dispatch(apologize('The Sandwich Shop', forPerson, error))
    );
  };
}

then it wouldn't necessarily make sense to have a generic error callback for a failure to fetch a secret sauce, as there might be different circumstances for fetching the sauce.

Thus I can see the thunk model a bit more flexible.

Possibly something like logging or maybe even the toggling of a "async in progress busy indicator" are more appropriate examples of middleware?

@gaearon , is this technique of using Thunk and distinct actions http://gaearon.github.io/redux/docs/api/applyMiddleware.html preferable to your answer above:

You can also write a custom middleware like this

export default function promiseMiddleware() {
  return (next) => (action) => {
    const { promise, ...rest } = action;
    if (!promise) {
      return next(action);
    }

    next({ ...rest, readyState: 'request' );
    return promise.then(
      (result) => next({ ...rest, result, readyState: 'success' }),
      (error) => next({ ...rest, error, readyState: 'failure' })
    );
  };
}

and use it instead of the default one.
This will let you write async action creators like

function doSomethingAsync(userId) {
  return {
    type: SOMETHING,
    promise: requestSomething(userId),
    userId
  };
}

and have them turn into

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, readyState: 'success' }
{ type: SOMETHING, userId: 2, readyState: 'failure' }

Also,

I think for the last part, you meant:

{ type: SOMETHING, userId: 2, readyState: 'request' }
{ type: SOMETHING, userId: 2, result, readyState: 'success' }
{ type: SOMETHING, userId: 2, error, readyState: 'failure' }

I'm guessing it just depends on whether one wants to create separate actions for the success or failure callbacks of the promise, rather than using the auto-generated one.

In your thunk example:

function makeASandwichWithSecretSauce(forPerson) {

  // Invert control!
  // Return a function that accepts `dispatch` so we can dispatch later.
  // Thunk middleware knows how to turn thunk async actions into actions.

  return function (dispatch) {
    return fetchSecretSauce().then(
      sauce => dispatch(makeASandwich(forPerson, sauce)),
      error => dispatch(apologize('The Sandwich Shop', forPerson, error))
    );
  };
}

then it wouldn't necessarily make sense to have a generic error callback for a failure to fetch a secret sauce, as there might be different circumstances for fetching the sauce.

Thus I can see the thunk model a bit more flexible.

Possibly something like logging or maybe even the toggling of a "async in progress busy indicator" are more appropriate examples of middleware?

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Aug 5, 2015

Collaborator

@justin808

Both are fine. Pick what's less verbose for you and what works better for your project. My suggestion is to start with using thunks, and if you see some pattern repeating, extract it into custom middleware. You can mix them too.

Collaborator

gaearon commented Aug 5, 2015

@justin808

Both are fine. Pick what's less verbose for you and what works better for your project. My suggestion is to start with using thunks, and if you see some pattern repeating, extract it into custom middleware. You can mix them too.

@gabrielgiussi

This comment has been minimized.

Show comment
Hide comment
@gabrielgiussi

gabrielgiussi Aug 8, 2015

I've created an ActionStore for separete the state of the triggered actions (loading, succeeded, failed) from the other state. But I don't known if this goes against the basis of Redux/Flux. I've posted in stackoverflow about this.

I've created an ActionStore for separete the state of the triggered actions (loading, succeeded, failed) from the other state. But I don't known if this goes against the basis of Redux/Flux. I've posted in stackoverflow about this.

@wmertens

This comment has been minimized.

Show comment
Hide comment
@wmertens

wmertens Aug 10, 2015

Contributor

@gabrielgiussi I think https://github.com/acdlite/redux-promise also can achieve what you want without you having to store promises in the state. The state is supposed to be serializable at all times.

Contributor

wmertens commented Aug 10, 2015

@gabrielgiussi I think https://github.com/acdlite/redux-promise also can achieve what you want without you having to store promises in the state. The state is supposed to be serializable at all times.

@gabrielgiussi

This comment has been minimized.

Show comment
Hide comment
@gabrielgiussi

gabrielgiussi Aug 10, 2015

@wmertens thanks for the advise. I will take a look to the repo but why my state would not be serializable? Or you say it only for I take note?

@wmertens thanks for the advise. I will take a look to the repo but why my state would not be serializable? Or you say it only for I take note?

@wmertens

This comment has been minimized.

Show comment
Hide comment
@wmertens

wmertens Aug 10, 2015

Contributor

@gabrielgiussi I didn't look very closely but it seemed like you were
putting promises or functions in the store. In any case, that project
should also work well I think.

On Mon, Aug 10, 2015, 19:15 gabrielgiussi notifications@github.com wrote:

@wmertens https://github.com/wmertens thanks for the advise. I will
take a look to the repo but why my state would not be serializable? Or you
say it only for I take note?


Reply to this email directly or view it on GitHub
#99 (comment).

Wout.
(typed on mobile, excuse terseness)

Contributor

wmertens commented Aug 10, 2015

@gabrielgiussi I didn't look very closely but it seemed like you were
putting promises or functions in the store. In any case, that project
should also work well I think.

On Mon, Aug 10, 2015, 19:15 gabrielgiussi notifications@github.com wrote:

@wmertens https://github.com/wmertens thanks for the advise. I will
take a look to the repo but why my state would not be serializable? Or you
say it only for I take note?


Reply to this email directly or view it on GitHub
#99 (comment).

Wout.
(typed on mobile, excuse terseness)

@gabrielgiussi

This comment has been minimized.

Show comment
Hide comment
@gabrielgiussi

gabrielgiussi Aug 10, 2015

Actually, in the store I put custom Action objects, they are just Immutable.Record with simple attribues (id, state, payload) and an action trigger that creates and returns a Promise, so I'm not putting Promises in the Store. But I'm probably breaking something somewhere else, je. Thanks @wmertens.

Actually, in the store I put custom Action objects, they are just Immutable.Record with simple attribues (id, state, payload) and an action trigger that creates and returns a Promise, so I'm not putting Promises in the Store. But I'm probably breaking something somewhere else, je. Thanks @wmertens.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Aug 11, 2015

Collaborator

@gabrielgiussi

and an action trigger that creates and returns a Promise

Don't put functions or anything else that isn't serializable, into the state.

Collaborator

gaearon commented Aug 11, 2015

@gabrielgiussi

and an action trigger that creates and returns a Promise

Don't put functions or anything else that isn't serializable, into the state.

@gabrielgiussi

This comment has been minimized.

Show comment
Hide comment
@gabrielgiussi

gabrielgiussi Aug 11, 2015

Sorry. I tried to say

and a function trigger that creates and returns a Promise

What I'm actually putting in the store is an Action object (the name was not the best):

export default class Action extends Immutable.Record({state: 'idle', api: null, type: null, payload: null, id: null}){
load(){
  return this.set('state','loading');
}

succeed(){
  return this.set('state','succeeded');
}

fail(){
  return this.set('state','failed');
}

ended(){
  return this.get('state') != 'loading' && this.get('state') != 'idle';
}

endedWithSuccess(){
  return this.get('state') == 'succeeded';
}

endedWithFailure(){
  return this.get('state') == 'failed';
}

trigger() {
  return (dispatch) => {
    dispatch({type: this.get('type') + '_START', action: this});
    let payload = this.get('payload');
    this.get('api').call({dispatch,payload}).then((result) => {
      dispatch({type: this.get('type') + '_SUCCESS',id: this.get('id'), result: result.result});
    }).catch((result) => {
        dispatch({type: this.get('type') + '_FAIL',id: this.get('id'), result: result.result});
      });
  }
}
}

Sorry. I tried to say

and a function trigger that creates and returns a Promise

What I'm actually putting in the store is an Action object (the name was not the best):

export default class Action extends Immutable.Record({state: 'idle', api: null, type: null, payload: null, id: null}){
load(){
  return this.set('state','loading');
}

succeed(){
  return this.set('state','succeeded');
}

fail(){
  return this.set('state','failed');
}

ended(){
  return this.get('state') != 'loading' && this.get('state') != 'idle';
}

endedWithSuccess(){
  return this.get('state') == 'succeeded';
}

endedWithFailure(){
  return this.get('state') == 'failed';
}

trigger() {
  return (dispatch) => {
    dispatch({type: this.get('type') + '_START', action: this});
    let payload = this.get('payload');
    this.get('api').call({dispatch,payload}).then((result) => {
      dispatch({type: this.get('type') + '_SUCCESS',id: this.get('id'), result: result.result});
    }).catch((result) => {
        dispatch({type: this.get('type') + '_FAIL',id: this.get('id'), result: result.result});
      });
  }
}
}
@ForbesLindesay

This comment has been minimized.

Show comment
Hide comment
@ForbesLindesay

ForbesLindesay Aug 16, 2015

Contributor

I've created a library for solving this problem (see #539) it works by having middleware return promises for pending actions, and waiting for all those promises to be resolved.

Contributor

ForbesLindesay commented Aug 16, 2015

I've created a library for solving this problem (see #539) it works by having middleware return promises for pending actions, and waiting for all those promises to be resolved.

@RanzQ RanzQ referenced this issue in ericclemmons/react-resolver Sep 19, 2015

Open

Redux Example #61

jsdmc referenced this issue in jsdmc/react-redux-router-crud-boilerplate Oct 7, 2015

@banderson5144

This comment has been minimized.

Show comment
Hide comment
@banderson5144

banderson5144 Oct 21, 2015

@gaearon this code you wrote https://github.com/rackt/redux/issues/99#issuecomment-112212639,

Is this something that is included the redux library or is it something I have to create manually? Sorry if this is a newb question, just getting into React / Flux (Redux). Just started this tutorial https://github.com/happypoulp/redux-tutorial

@gaearon this code you wrote https://github.com/rackt/redux/issues/99#issuecomment-112212639,

Is this something that is included the redux library or is it something I have to create manually? Sorry if this is a newb question, just getting into React / Flux (Redux). Just started this tutorial https://github.com/happypoulp/redux-tutorial

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Oct 21, 2015

Collaborator

@banderson5144

It's not included. It's just there to give you an idea of what you can do鈥攂ut you're free to do it differently.
Something similar was published as https://github.com/pburtchaell/redux-promise-middleware.

Collaborator

gaearon commented Oct 21, 2015

@banderson5144

It's not included. It's just there to give you an idea of what you can do鈥攂ut you're free to do it differently.
Something similar was published as https://github.com/pburtchaell/redux-promise-middleware.

@ReadmeCritic ReadmeCritic referenced this issue in erikras/react-redux-universal-hot-example Nov 19, 2015

Merged

Update README URLs based on HTTP redirects #577

@DominicTobias

This comment has been minimized.

Show comment
Hide comment
@DominicTobias

DominicTobias Dec 17, 2015

Thanks for this useful info. I wanted to pick your brains on reseting a store -

  • You reset the store state for a new user
  • You wait on some async actions to complete before giving the user the store and html
  • A previously running async action for another user completes and your store gets polluted

How did you guys solve that/have any ideas how to? Just a new store for each user would work instead?

Thanks for this useful info. I wanted to pick your brains on reseting a store -

  • You reset the store state for a new user
  • You wait on some async actions to complete before giving the user the store and html
  • A previously running async action for another user completes and your store gets polluted

How did you guys solve that/have any ideas how to? Just a new store for each user would work instead?

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Dec 17, 2015

Collaborator

Are you talking about server rendering? Create a new store on every request. We have a guide for server rendering in the docs.

Collaborator

gaearon commented Dec 17, 2015

Are you talking about server rendering? Create a new store on every request. We have a guide for server rendering in the docs.

@DominicTobias

This comment has been minimized.

Show comment
Hide comment
@DominicTobias

DominicTobias Dec 17, 2015

Thanks I'll do that

Thanks I'll do that

@chemoish

This comment has been minimized.

Show comment
Hide comment
@chemoish

chemoish Jan 22, 2016

After trying to understand鈥

Is this too naive? (no one else seems to do this鈥攊 think)

// server.js
app.use(function (req, res) {
    match({鈥, function (error, redirectLocation, renderProps) {
        鈥

        if (renderProps) {
            const store = configureStore();

            const promises = renderProps.components.map(function (component, index) {
                if (typeof component.fetchData !== 'function') {
                    return false;
                }

                return component.fetchData(store.dispatch);
            });

            Promise.all(promises).then(function () {
                res.status(200).send(getMarkup(store, renderProps));
            });
        }
    })
});
// home.js
export class Home extends Component {
    static fetchData() {
        return Promise.all([
            dispatch(asyncAction);
        ]);
    },

    componentDidMount() {
        const { dispatch } = this.props;

        Home.fetchData(dispatch);
    }
}

export default connect()(Home);
// action.js
export function asyncAction() {
    return (dispatch, getState) => {
        dispatch(request);

        return fetch(鈥)
            .then(response => response.json())
            .then(data => dispatch(requestSuccess(data)))
        ;
    }
}

I was also trying to figure out a solution for @mattybow's question https://github.com/rackt/redux/issues/99#issuecomment-112980776 (nested components managing data fetching), but no such success (wasn't sure on how to collect promises from componentWillMount).

After trying to understand鈥

Is this too naive? (no one else seems to do this鈥攊 think)

// server.js
app.use(function (req, res) {
    match({鈥, function (error, redirectLocation, renderProps) {
        鈥

        if (renderProps) {
            const store = configureStore();

            const promises = renderProps.components.map(function (component, index) {
                if (typeof component.fetchData !== 'function') {
                    return false;
                }

                return component.fetchData(store.dispatch);
            });

            Promise.all(promises).then(function () {
                res.status(200).send(getMarkup(store, renderProps));
            });
        }
    })
});
// home.js
export class Home extends Component {
    static fetchData() {
        return Promise.all([
            dispatch(asyncAction);
        ]);
    },

    componentDidMount() {
        const { dispatch } = this.props;

        Home.fetchData(dispatch);
    }
}

export default connect()(Home);
// action.js
export function asyncAction() {
    return (dispatch, getState) => {
        dispatch(request);

        return fetch(鈥)
            .then(response => response.json())
            .then(data => dispatch(requestSuccess(data)))
        ;
    }
}

I was also trying to figure out a solution for @mattybow's question https://github.com/rackt/redux/issues/99#issuecomment-112980776 (nested components managing data fetching), but no such success (wasn't sure on how to collect promises from componentWillMount).

@dbismut dbismut referenced this issue in djhi/my-nutrition Jan 23, 2016

Open

Redux-meteor discussion #3

@ms88privat

This comment has been minimized.

Show comment
Hide comment
@ms88privat

ms88privat Feb 17, 2016

@chemoish I'm also trying to get my head around server-side rendering with react and redux. The example in the documentation does not handle this use case very well. I do not want to specify and couple every API request on the server with my components again. The component only should specify how to get the data needed (which the server then should pick up).

Your solutions looks quite good to accomplish that. Did this work out for you? Thanks

Edit: I'm correct that "componentDidMount" does not get triggered again on the client when it is rendered on the server?

@chemoish I'm also trying to get my head around server-side rendering with react and redux. The example in the documentation does not handle this use case very well. I do not want to specify and couple every API request on the server with my components again. The component only should specify how to get the data needed (which the server then should pick up).

Your solutions looks quite good to accomplish that. Did this work out for you? Thanks

Edit: I'm correct that "componentDidMount" does not get triggered again on the client when it is rendered on the server?

@chemoish

This comment has been minimized.

Show comment
Hide comment
@chemoish

chemoish Feb 17, 2016

@ms88privat I haven't gotten much feedback on the solution yet, nor have tested its limits.

However, the solution posed above requires each page to know the data for all of its children components. I haven't dug deeper into have nested components worry about data management themselves (due to collecting nested promises).

It seems to be doing what you would expect, so its good enough for me for now.


componentDidMount will get triggered again (See https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount). You can use this or another lifecycle method that suits your needs.

I get around this by preventing the fetch code from executing if the store is already full (or whatever business logic you see fit).

Examine https://github.com/reactjs/redux/blob/master/examples/async/actions/index.js#L47 for an idea of what I am talking about.

@ms88privat I haven't gotten much feedback on the solution yet, nor have tested its limits.

However, the solution posed above requires each page to know the data for all of its children components. I haven't dug deeper into have nested components worry about data management themselves (due to collecting nested promises).

It seems to be doing what you would expect, so its good enough for me for now.


componentDidMount will get triggered again (See https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount). You can use this or another lifecycle method that suits your needs.

I get around this by preventing the fetch code from executing if the store is already full (or whatever business logic you see fit).

Examine https://github.com/reactjs/redux/blob/master/examples/async/actions/index.js#L47 for an idea of what I am talking about.

@ms88privat

This comment has been minimized.

Show comment
Hide comment
@ms88privat

ms88privat Feb 17, 2016

@chemoish

I get around this by preventing the fetch code from executing if the store is already full

Okey, I got that. Thanks.

However, the solution posed above requires each page to know the data for all of its children components.

Maybe I misread your solution, but isn't this a necessary requirement regardless of the server-side rendering? (e.g. it should render the same state, if I refresh on the current route, even if it is a SPA)

@chemoish

I get around this by preventing the fetch code from executing if the store is already full

Okey, I got that. Thanks.

However, the solution posed above requires each page to know the data for all of its children components.

Maybe I misread your solution, but isn't this a necessary requirement regardless of the server-side rendering? (e.g. it should render the same state, if I refresh on the current route, even if it is a SPA)

@chemoish

This comment has been minimized.

Show comment
Hide comment
@chemoish

chemoish Feb 17, 2016

It would, but you may want a nested component manage its own data fetching, for whatever reason.

For instance, a component that is repeated on many pages, but each page doesn't have much data fetching needs.

It would, but you may want a nested component manage its own data fetching, for whatever reason.

For instance, a component that is repeated on many pages, but each page doesn't have much data fetching needs.

@ms88privat

This comment has been minimized.

Show comment
Hide comment
@ms88privat

ms88privat Feb 17, 2016

@chemoish I'm not sure if we are on the same page. Let me try to explain what my point of view is.

For example I got three nested components:

  • component1 (static dataFetch1)
    • component2 (static dataFetch2)
      • component3 (static dataFetch3)

Each of them have there own "componentDidMount" methods, with there own dataFetching declarations (dispatching actions via its static dataFetching method).

If I do not have sever-side rendering and I refresh the current URL, my components will mount and trigger all the actions needed to load all the required data afterwards.

With server-side rendering, your match function and renderProps will extract all three components, so I can access all of the static dataFetching methods, which will then allow me to fetch all the data needed for the initial server-side rendering?

Do you have a reference to your match function from your provided example? Thx.

@chemoish I'm not sure if we are on the same page. Let me try to explain what my point of view is.

For example I got three nested components:

  • component1 (static dataFetch1)
    • component2 (static dataFetch2)
      • component3 (static dataFetch3)

Each of them have there own "componentDidMount" methods, with there own dataFetching declarations (dispatching actions via its static dataFetching method).

If I do not have sever-side rendering and I refresh the current URL, my components will mount and trigger all the actions needed to load all the required data afterwards.

With server-side rendering, your match function and renderProps will extract all three components, so I can access all of the static dataFetching methods, which will then allow me to fetch all the data needed for the initial server-side rendering?

Do you have a reference to your match function from your provided example? Thx.

@DominicTobias

This comment has been minimized.

Show comment
Hide comment
@DominicTobias

DominicTobias Feb 17, 2016

@ms88privat renderProps.components is an array of router components, it doesn't go deeper than that. @chemoish meant that with his implementation you cannot describe the data fetching needs on deeper components.

@ms88privat renderProps.components is an array of router components, it doesn't go deeper than that. @chemoish meant that with his implementation you cannot describe the data fetching needs on deeper components.

@ms88privat

This comment has been minimized.

Show comment
Hide comment
@ms88privat

ms88privat Feb 17, 2016

@DominicTobias thx, do you have a solution to this problem? Is there a possibility to get all the nested components?

@DominicTobias thx, do you have a solution to this problem? Is there a possibility to get all the nested components?

@sompylasar

This comment has been minimized.

Show comment
Hide comment
@sompylasar

sompylasar Feb 17, 2016

Probably this can help? https://github.com/gaearon/react-side-effect
Used to collect all meta tags from nested elements: https://github.com/nfl/react-helmet

Probably this can help? https://github.com/gaearon/react-side-effect
Used to collect all meta tags from nested elements: https://github.com/nfl/react-helmet

@vtambourine

This comment has been minimized.

Show comment
Hide comment
@vtambourine

vtambourine Mar 11, 2016

Sorry for bumping this discussion again, but I have recently run into the same problem of prefilling state with async action.

I can see that @erikras moved his boilerplate project to redux-async-connect. I wonder, if somebody found another solution?

Sorry for bumping this discussion again, but I have recently run into the same problem of prefilling state with async action.

I can see that @erikras moved his boilerplate project to redux-async-connect. I wonder, if somebody found another solution?

@ctrlplusb

This comment has been minimized.

Show comment
Hide comment
@ctrlplusb

ctrlplusb Mar 18, 2016

@vtambourine I have been looking at https://github.com/markdalgleish/redial which is quite helpful

@vtambourine I have been looking at https://github.com/markdalgleish/redial which is quite helpful

@vtambourine

This comment has been minimized.

Show comment
Hide comment
@vtambourine

vtambourine Mar 18, 2016

Yes, I have looked through it. But I didn't get, how to make sure data
fetching hooked will not run second time after reinitialization code to n
client.
On 袩褌, 18 屑邪褉褌邪 2016 谐. at 22:54, Sean Matheson notifications@github.com
wrote:

@vtambourine https://github.com/vtambourine I have been looking at
https://github.com/markdalgleish/redial which is quite helpful


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#99 (comment)

Yes, I have looked through it. But I didn't get, how to make sure data
fetching hooked will not run second time after reinitialization code to n
client.
On 袩褌, 18 屑邪褉褌邪 2016 谐. at 22:54, Sean Matheson notifications@github.com
wrote:

@vtambourine https://github.com/vtambourine I have been looking at
https://github.com/markdalgleish/redial which is quite helpful


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#99 (comment)

@isTravis

This comment has been minimized.

Show comment
Hide comment
@isTravis

isTravis May 12, 2016

Also curious if anyone has found a stable solution for this challenge. I love @erikras's boilerplate, but as @vtambourine mentioned, it has moved to redux-async-connect which seems like it may not be a stable long-term solution: #81 Is redux-async-connect dead?.

Also curious if anyone has found a stable solution for this challenge. I love @erikras's boilerplate, but as @vtambourine mentioned, it has moved to redux-async-connect which seems like it may not be a stable long-term solution: #81 Is redux-async-connect dead?.

@ReadmeCritic ReadmeCritic referenced this issue in erikras/react-redux-universal-hot-example May 16, 2016

Open

Update README URLs based on HTTP redirects #1157

@AVVS

This comment has been minimized.

Show comment
Hide comment
@AVVS

AVVS May 24, 2016

@vtambourine there is a fork thats available at https://github.com/makeomatic/redux-connect and is well-maintained. It has similar API with a few changes to it, check it out if you are interested

AVVS commented May 24, 2016

@vtambourine there is a fork thats available at https://github.com/makeomatic/redux-connect and is well-maintained. It has similar API with a few changes to it, check it out if you are interested

@peter-mouland

This comment has been minimized.

Show comment
Hide comment
@peter-mouland

peter-mouland Sep 3, 2016

Contributor

for those interested in a redux solution with middleware as mentioned by @gaearon I have an example project which implements this technique and allows the components themselves request the data they need server-side

https://github.com/peter-mouland/react-lego#redux-with-promise-middleware

Contributor

peter-mouland commented Sep 3, 2016

for those interested in a redux solution with middleware as mentioned by @gaearon I have an example project which implements this technique and allows the components themselves request the data they need server-side

https://github.com/peter-mouland/react-lego#redux-with-promise-middleware

@serraventura

This comment has been minimized.

Show comment
Hide comment
@serraventura

serraventura Oct 18, 2016

How to unit test action creator with this approach?

How to unit test action creator with this approach?

@rufuspollock rufuspollock referenced this issue in datahq/frontend-showcase-js Mar 9, 2017

Closed

[future] How to do Redux store (if we do it again) #128

@apapacy apapacy referenced this issue in wellyshen/react-cool-starter Jul 19, 2017

Merged

promised middlevare released #80

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