Comments (17)
^ That's essentially what I ended up with and it's been working OK for me so far.
Only difference with mine is that my linter enforces a consistent return statement so my promise is:
const result = !isLoaded(getState()) ? dispatch(load()) : null;
return __CLIENT__ ? null : result;
from redux-connect.
@jaraquistain if you supply key
alongside promise
- you will be able to check loaded data easier:
use getState().reduxAsyncConnect.loadState[key]
to check for loading state, it has 3 props:
{
loading: Boolean,
loaded: Boolean,
error: Object,
}
Also, the response data would be stored at getState().reduxAsyncConnect[key]
Logic for this is here: https://github.com/makeomatic/redux-connect/blob/master/modules/store.js
from redux-connect.
@badtant that way client wont wait for result of the promise, and, therefore, wont delay routing. So yes, if that's what you want - it is the way to go
from redux-connect.
There are 2 things for that:
https://github.com/makeomatic/redux-connect/blob/master/modules/components/AsyncConnect.js#L35-L42
Here we have a check that is performed on whether data was loaded or not
https://github.com/makeomatic/redux-connect/blob/master/modules/components/AsyncConnect.js#L58
If you pass filter
props to ReduxAsyncComponents - this is where you can add logic to whether you need to load it or not (defer example) - it should be different on server & client.
As for data not loading on client - there is pretty simply boolean logic here, it is either completely loaded or not and thats what redux-connect is tracking. If we need to do partial checks - then we'll have to understand when to set data as not loaded. For now load is always triggered after routing - and it's ultimately your responsibility to avoid fetching same data twice. You can incorporate those checks into your own actions in redux, for instance
from redux-connect.
TL;DR: I figured out that if your promise
property returns a promise then the router will not transition until all the promises have been resolved, whereas if your promise
does not return anything (or something that isn't an unresolved promise) then the next route is rendered immediately, even while the fetches are still loading (which is exactly what I wanted). Given the way redux-connect
works I don't currently want to pass a filter
into <ReduxAsyncConnect />
because I do want the data to load in all cases. I don't know why redux-async-connect
would still load things on the client that were filtered out.
EG:
I've got a /networks/:id
route that renders a Network
container. This Network
container requires me to externally fetch a list of NETWORK_SUBDOMAN
data. The container also indicates whether or not any of the data is currently loading via a spinner. For the sake of argument lets say I've also got a /home
page that contains a link pointing to /networks/123
. If my mapAsyncStateToProps
is this:
const asyncStateToProps = NETWORK_SUBDOMAINS.map(subdomain => ({
promise: ({ store: { dispatch, getState }, params }) => {
const networkUrl = urlFromId(params.id);
return !isLoaded(getState(), networkUrl, subdomain) ? dispatch(load(networkUrl, subdomain)) : Promise.resolve();
}
}));
Then when I click my link on /home
the page will sit until ALL of the data for /networks/123
is loaded, THEN transition to the view. When /networks/123
is visible there is no spinner because all the data has finished loading
However, if my mapAsyncStateToProps
is this:
const asyncStateToProps = NETWORK_SUBDOMAINS.map(subdomain => ({
promise: ({ store: { dispatch, getState }, params }) => {
const networkUrl = urlFromId(params.id);
!isLoaded(getState(), networkUrl, subdomain) ? dispatch(load(networkUrl, subdomain)) : Promise.resolve();
}
}));
(the only difference being a lack of a return
at the bottom)
Then when I click the link on /home
, the /networks/123
view is (almost) immediately visible and shows the spinner indicating the data is still loading. When the data is finished loading the spinner disappears and the data replaces it, as expected.
I definitely follow what you're saying and based on that the behavior I'm seeing is exactly as expected. I guess I just don't understand the core differences between redux-async-connect
and this fork, because redux-async-connect
behaves entirely differently in the situation I described.
I was previously passing filter
to <ReduxAsyncConnect />
in my client.js
like this:
// Render routes using ReduxAsyncConnect
function renderRouter(props) {
function filter(item) { return !item.deferred; }
return <ReduxAsyncConnect { ...props } helpers={{ client }} filter={filter} />;
}
// The configured Router component for the app
const component = (
<Router render={renderRouter} history={enhancedHistory}>
{getRoutes(store)}
</Router>
);
and in the case of redux-connect
I can fully understand how filtering out fetches that contain deferred
would mean that that data is never fetched on the client. What doesn't make sense is why redux-async-connect
would still fetch things that are filtered out, but after the new route renders. Maybe there's some magic boilerplate code handling that part? I haven't seen anything that would do something like that.
Anyway, thanks for your response it was very helpful
from redux-connect.
Also, I should probably close this since I've figured out the answer to my original question
from redux-connect.
@jaraquistain in the boilterplate you are using they have methods to short-circuit loading of data if it was already loaded. Basically when you try to fetch data - you first check if it's loaded and if it was - you just return it via Promise.resolve() or just simple return - doesn't really matter since it's wrapper.
from redux-connect.
UPDATE: Slight modification to what I said earlier.
never returning the actual promise inside of promise
as I said I was doing earlier actually breaks server side data fetching because the server thinks the fetch is immediatly finished and sends the response. I've modified my mapAsyncStateToProps
to be the following:
const asyncStateToProps = NETWORK_SUBDOMAINS.map(subdomain => ({
promise: ({ store: { dispatch, getState }, params }) => {
const networkUrl = urlFromId(params.id);
const result = !isLoaded(getState(), networkUrl, subdomain) ? dispatch(load(networkUrl, subdomain)) : Promise.resolve();
if (!__CLIENT__) { return result; }
}
}));
Now I return the promise on the server and not the client in cases where I don't want the fetch to block the transition. Not the prettiest but it actually works until I think of something better.
from redux-connect.
alter result
so that instead of Promise.resolve() it would return the actual value, that way it's effectively a short-circuit.
Also whats isLoaded
code?
from redux-connect.
@AVVS ok I'll try replacing Promise.resolve()
with the actual values.
isLoaded
is my function that I call to determine whether or not whatever we want to fetch is already in the current state or if we need to dispatch the action to get it from the server. It looks like this:
export function isLoaded(globalState, networkUrl, subdomain) {
const thisNetwork = globalState.networks[networkUrl] || {};
return (subdomain ? (thisNetwork[subdomain] || {}) : thisNetwork).loaded;
}
from redux-connect.
@AVVS Excellent tip, thank you!
from redux-connect.
@jaraquistain I'm trying to do exactly the same thing as you but I don't really follow what I should change :)
I've removed all my "deferred: true" and the filter from the client code "filter={item => !item.deferred}"
Now server rendering works fine but I don't get my spinner when transitioning on the client. Maybe you can point me in the right direction?
My async connect code is like this now:
@asyncConnect([{
promise: ({store}) => {
if (!isLoaded(store.getState())) {
return store.dispatch(loadAction());
}
}
}])
from redux-connect.
rendering is delayed until all the data from async connect is loaded, so you wont see it. If you need a spinner you should dispatch those actions in componentDidMount or not return a promise from async connect, otherwise it will wait until its done
from redux-connect.
Thanks!
So right now I have this which seems to be working. Is that the way to go?
@asyncConnect([{
promise: ({store}) => {
const result = !isLoaded(store.getState()) ? store.dispatch(loadAction()) : null;
if (!__CLIENT__) {
return result;
}
}
}])
from redux-connect.
Was just going through this since I too was wondering how to stop it from blocking routing on the browser, just wondering if someone found a cleaner alternative to the solutions mentioned above?
from redux-connect.
@lakshyaranganath I couldn't think of anything better so I've been sticking with what was discussed above
from redux-connect.
Ahh alright! Thanks again! :)
Regards,
Lakshya Ranganath
Freelance Web Developer
+91 90352 09244
On 9 Sep 2016 23:25, "Jonathan Araquistain" [email protected]
wrote:
@lakshyaranganath https://github.com/lakshyaranganath I couldn't think
of anything better so I've been sticking with what was discussed above—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#3 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AHMoDMfOB_MCzDuLlRTIx20rHRgZnv7Mks5qoZ2fgaJpZM4IZhkD
.
from redux-connect.
Related Issues (20)
- Use it with simple async fetch?
- Lazy component load HOT 4
- Suggestion: previous location and params
- asyncConnect does not fire with browser back button
- can't install 7.0.0 HOT 1
- Can't resolve 'react-router-config/renderRoutes' in node_moduels/redux-connect/lib/components HOT 1
- How to use with redux-thunk ? HOT 1
- asyncConnect promises are not called when running jest test
- Wait for Nested Promises to resolve HOT 2
- Wait to render before promise is resolved. HOT 13
- Passing async response data as prop. HOT 1
- Using ownProps inside the preload action HOT 2
- react-redux 6.0.0 support HOT 8
- Router render v3 and ReduxAsyncConnect
- Component attempts to render before asyncConnect promise is fired/resolved
- Cannot read property 'store' of undefined HOT 3
- support for react-router 5 and react-redux 7?
- Use JSX routes insted of static array of routes
- Does it support react router 3?
- How to use library with code splitting with React.lazy and use declarative routing? HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from redux-connect.