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

Best API for client-side data loading #2638

Closed
jlongster opened this issue Dec 3, 2015 · 23 comments
Closed

Best API for client-side data loading #2638

jlongster opened this issue Dec 3, 2015 · 23 comments

Comments

@jlongster
Copy link
Contributor

I'm sure this has been talked about a lot, but it doesn't seem resolved. @ryanflorence mentioned filing it: https://twitter.com/ryanflorence/status/672163238482739210

I thought the createElement was a decent API for triggering data fetching, but the problem is that it's fired in the middle of rendering. That means that we can't change any state (shouldn't call setState within render); for example redux will update the app state which is fine but connecting components will trigger a render immediately. See https://github.com/jlongster/react-redux-universal-hot-example/pull/2/files These will be triggered because the app state has been updated to reflect that an async request has "started" (the "finished" events will of course come later and would trigger renders outside of rendering).

So what's the best way to:

  1. On the client-side, when a routing component is created and mounted, automatically begin an async request to fetch data
  2. Fire multiple data fetching requests in parallel for the list of nested routing components

It's easy to do data fetching on the server: we call match and get a static list of components and trigger the requests for all of them. There's a PR on react-redux-universal-hot-example to actually do this client-side as well, but I think that's way too much code: https://github.com/jlongster/react-redux-universal-hot-example/pull/4/files

I'm not really opinionated about this, honestly, I just want something that works. What does everyone think?

EDIT: Ryan has async-props, https://github.com/rackt/async-props, which looks cool. I can point people to that, but I'd also like to explain a basic strategy for people wanting to roll their own. I get this question a lot with redux-simple-router.

@iam4x
Copy link
Contributor

iam4x commented Dec 3, 2015

@taion
Copy link
Contributor

taion commented Dec 3, 2015

@jlongster Ping me on Reactiflux when you get a chance - I have some thoughts but I don't have them in a coherent enough way to formulate a comment here.

@dlmr
Copy link

dlmr commented Dec 3, 2015

@jlongster I created my own RoutingContext based on @ryanflorence AsyncProps for managing data fetching client side. https://github.com/vgno/roc-web-react/blob/master/src/app/client/redux-context/index.js. It assumes that the components uses https://github.com/markdalgleish/react-fetcher for managing data fetching.

It's an early version but seems to work great for me at the moment.

@timdorr
Copy link
Member

timdorr commented Dec 4, 2015

Sounds like this might be provided by #2614.

@timdorr
Copy link
Member

timdorr commented Dec 5, 2015

@jlongster Looks like the proposed render API in #2646 should provide this. Feel free to provide feedback if you don't think it will.

@taion
Copy link
Contributor

taion commented Dec 5, 2015

@jlongster

Conceptually, the way we handle this with the Relay integration is that data are assigned to a particular key. On render, check whether there's anything under the key, and whether an error has occurred. If neither is true, then we know that data is still pending, and we can do whatever is appropriate.

This way you don't need to explicitly indicate "loading start"; it's implicit whenever you want data that you don't yet have.

There's a broader question here about how data loading should interact with history transitions that we'll have to defer to a later point, though. I'll just note for now that on non-SPA pages, nothing really changes until the server's gathered all the data it needs to respond to you, whereas right now we work in 3 steps -

  1. Completion of transition on history
  2. Completion of route matching on <Router>
  3. Completion of data fetching from AsyncProps or something else

@jlongster
Copy link
Contributor Author

@timdorr @taion Unfortunately I haven't had time to fully look into this. I wish I could give feedback but I'm pretty much willing to do whatever you all tell me to :) If there's a concrete API I can test out I'll try it. Otherwise I'm not sure I'll have time this next week to discuss; I'll be at a Mozilla work week.

@timdorr timdorr added this to the v1.1 milestone Dec 6, 2015
@MrEfrem
Copy link

MrEfrem commented Dec 8, 2015

@taion and how to be if it is necessary this received from the server to transform before UI begins is rendered? I for example use Map objects in redux a store. But Map is serialized in an array for transmission to the client. And on his client it is necessary to transform again to Map and just this operation I want to execute prior to rendering of UI and that didn't flicker what messages on that that something is processed.

@timdorr
Copy link
Member

timdorr commented Dec 8, 2015

@MrEfrem That's a redux issue. It should be handled wherever you're deserializing the data coming from the server, which isn't really related to what we're talking about here. Feel free to hop on Discord or Stack Overflow to get your problem solved.

@MrEfrem
Copy link

MrEfrem commented Dec 8, 2015

@timdorr You faced that as Map is serialized in an array?
I can create such nested structure where also ImmutableJS of structure and Map and Set will be used in the stora. It is impossible to automate deserialising of this business since the architecture stor every time can be unpredictable. Therefore I consider that it not a problem of redux, and completely my care to tell redux about architecture stor.
For implementation of these things I also need normalization of the status transferred from the server and I for 99% am sure that mechanisms for executions of my task shall be put in react-router.
And on stackowerflow I created a question and wrote to discord about that why in onEnter if I execute instruction async await, I receive an error in the console about mismatch of checksum, but me for some reason who can't answer.
http://stackoverflow.com/questions/34096850/how-to-synchronously-prefetch-data-in-client-side
https://discordapp.com/channels/102860784329052160/103538345837068288

@timdorr
Copy link
Member

timdorr commented Dec 8, 2015

@MrEfrem Yes, that is a redux issue. Just don't use Map and Set in your store. But let's not continue this discussion here, please. This is unrelated to the issue at hand.

@MrEfrem
Copy link

MrEfrem commented Dec 8, 2015

@timdorr I use Map since it provides saving an order of elements as they were added to it, in difference from Object where it is necessary to use some haque.
But you are right we won't discuss it here, but I don't understand why you disagree with that that it is necessary to provide such API which would allow to solve these problems and there can be still others, already to solve it to us to developers of a finite software, we need it or not.

@timdorr
Copy link
Member

timdorr commented Dec 8, 2015

@MrEfrem This is issue is about when to load data, not how to load data. Your issue is the latter and doesn't have anything to do with the router.

@MrEfrem
Copy link

MrEfrem commented Dec 8, 2015

@timdorr It was simply the example for what it is necessary for me. But I consider that there shall be an opportunity to delay rendering of a reception to execute any actions to it (including asynchronous). Need of full implementation of this opportunity can appear in hundreds of different other situations and if not now to consider it, somebody again will lift then the same subject.

@taion
Copy link
Contributor

taion commented Dec 18, 2015

Is there anything else to do on this issue?

@MrEfrem
Copy link

MrEfrem commented Dec 18, 2015

And unless the result of this issue is received? Where to look at the best way?

@taion
Copy link
Contributor

taion commented Dec 18, 2015

"Do what AsyncProps does".

@MrEfrem
Copy link

MrEfrem commented Dec 18, 2015

They solve a problem of a fetch of data prior to rendering?

@ryanflorence
Copy link
Member

I think when we release/document the render prop, have a guide about middleware components, and update Async Props, we can close this issue.

@taion
Copy link
Contributor

taion commented Dec 18, 2015

👍

@ndreckshage
Copy link

@jlongster @ryanflorence React Router 2 is really nice + enables some interesting things. I just released a new open source project I've been working on that has handles data fetching & helps structure reducers with react router.

https://github.com/raisemarketplace/ground-control

@perrin4869
Copy link
Contributor

What about loading synchronous dependencies? I asked this question in discord but couldn't get an answer. Let's say for example I wanna inject an i18n object into my App component, as in <App i18n={i18n} />, which is different on the client and on the server and in test environments. How do I render that application in with react-router? The following didn't work, even though it was suggested in discord:

var i18n = new i18n(options);
<Router history={browserHistory}>
    <Route path="/" component={App} i18n={i18n} />
</Router>

@taion taion removed this from the v2 milestone Feb 20, 2016
@taion
Copy link
Contributor

taion commented Mar 30, 2016

Looks like async-props has been updated, and we have another issue to track docs updates, plus an ongoing rewrite effort. As such, there's nothing more to track on this issue.

@taion taion closed this as completed Mar 30, 2016
@lock lock bot locked as resolved and limited conversation to collaborators Jan 22, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants