Giter Site home page Giter Site logo

Comments (17)

jaraquistain avatar jaraquistain commented on August 25, 2024 11

^ 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.

AVVS avatar AVVS commented on August 25, 2024 2

@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.

AVVS avatar AVVS commented on August 25, 2024 1

@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.

AVVS avatar AVVS commented on August 25, 2024

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.

jaraquistain avatar jaraquistain commented on August 25, 2024

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.

jaraquistain avatar jaraquistain commented on August 25, 2024

Also, I should probably close this since I've figured out the answer to my original question

from redux-connect.

AVVS avatar AVVS commented on August 25, 2024

@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.

jaraquistain avatar jaraquistain commented on August 25, 2024

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.

AVVS avatar AVVS commented on August 25, 2024

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.

jaraquistain avatar jaraquistain commented on August 25, 2024

@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.

jaraquistain avatar jaraquistain commented on August 25, 2024

@AVVS Excellent tip, thank you!

from redux-connect.

badtant avatar badtant commented on August 25, 2024

@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.

AVVS avatar AVVS commented on August 25, 2024

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.

badtant avatar badtant commented on August 25, 2024

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.

whilelucky avatar whilelucky commented on August 25, 2024

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.

jaraquistain avatar jaraquistain commented on August 25, 2024

@lakshyaranganath I couldn't think of anything better so I've been sticking with what was discussed above

from redux-connect.

whilelucky avatar whilelucky commented on August 25, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.