ericclemmons / react-resolver

Async rendering & data-fetching for universal React applications.
https://ericclemmons.github.io/react-resolver
Other
1.65k stars 52 forks source link

Add hooks for props, pre-resolve, post-resolve, and rejected #41

Closed goatslacker closed 9 years ago

goatslacker commented 9 years ago

I'd love to know when all props have resolved or rejected so I can hook into this and add some nice alt support for caching resolver data.

Example API:

@resolve({
  props: {
    users(props) {
      const url = `https://api.github.com/repos/${props.user}/${props.repo}/stargazers`;
      return axios.get(url).then(response => response.data);
    },
  },

  onResolved(props) {
    AltActions.resolved(props);
  },

  onRejected(props) {
    AltActions.failed(props);
  }
}
ericclemmons commented 9 years ago

Wait a tick, isn't this already #39? You just like making issues for me, don'tcha! :D

For my own edification, what's the difference in:

@resolve({
  props: {
    users(props) {
      const url = `https://api.github.com/repos/${props.user}/${props.repo}/stargazers`;

      return axios.get(url).then(response => {
        AltActions.resolved(response.data);

        return response.data
      }, AltActions.failed);
    },
  },
}

(I readily admit I don't grasp the subtle differences!)

goatslacker commented 9 years ago

The difference is that if I have twenty props I'd have to add those handlers to every single one, this centralizes the logic to just one handler.

Not necessarily #39 since that just deals with loading/failed rendering states whereas this deals with resolved/rejected state and returns nothing.

While we're on this topic I'd also like hooks for when before a prop is resolved:

@resolve({
  // similar to shouldComponentUpdate, perhaps you want to conditionally resolve certain props depending on store state or whatever.
  shouldResolve() {
    return true;
  }

  // pre-hook for resolving a prop
  willResolve(prop, value) {

    // if the prop is user then lets check if the store has it first.
    if (prop === 'user') {

      // I hijack the resolver, lets not call my original function but instead use this
      if (UserStore.has('user')) return Promise.resolve(UserStore.getUser())
    }

    // value is the promise, or we can just return undefined and resolver can go on its merry way.
    return value
  }
})

I've updated the title accordingly.

ericclemmons commented 9 years ago

This is how I got around that scenario:

resolve: {
  user: function(props, context) {
    return UserActions.load(context.params.userId);
  },
}

where UserActions has:

load: function(id) {
  return UserStore.get(id) || UserActions.fetch(id);
}

Not saying to do this, as this is a very valid scenario. In my case, I opted to remove as much complexity from the container as possible.

I want to think about all 400 issues you opened today so I can ensure the changes are consistent.

I do like the idea of lifecycle events...

blainekasten commented 9 years ago

I do like this idea also.

max-zelinski commented 9 years ago

@ericclemmons in your example UserActions.fetch(id); returns promise, right? Is that flux?

ericclemmons commented 9 years ago

@max-zelinski Correct. This way, if the data exits, it'll be immediately returned & resolved via UserStore.get. Otherwise, react-resolver will load the Promise returned by UserActions.fetch.

And, AFAIK, anything that follows the Flux uni-directional event flow is considered "flux". You can still use constants like FETCH, FETCH_SUCCESS and FETCH_ERROR behind the scenes. The promise is the only async mechanism that works reliably on the server. (Callbacks do of course, but aren't re-implemented yet!)

ericclemmons commented 9 years ago

Architecturally, this is a bit rough in v1. v2 has a much cleaner solution for handling this that'll come in post-launch...

livemixlove commented 8 years ago

Any updates on this? And another question... should I be using react-resolver, or is something else out there the preferred method? It doesn't seem like the project is being updated much.

livemixlove commented 8 years ago

I'm looking at this: https://github.com/reactjs/react-router/commit/97dbf2ddc1cc778b8d6c3d69ae52200e578f22f9

ericclemmons commented 8 years ago

@livemixlove This project became less useful once the community went all-in on Redux (myself included).

Our production up using react, react-resolver, and react-router (v1) uses the method I indicated above.

But there's another maintainer now that can take a look @ this. The lifecycle thing was always rough to figure out, and frankly becomes cleaner with a single app state (e.g. Redux).

livemixlove commented 8 years ago

This was my suspicion. Thanks for the response!