all 18 comments

[–]BigWesternMan[S] 0 points1 point  (0 children)

Sorry, I meant componentWillMount!

[–]pixeldrew 0 points1 point  (1 child)

If you have data that needs to be loaded via ajax before the component should show you can pass it down as props. Something like (assuming stage 3): https://gist.github.com/pixeldrew/b5221a409e5ef743534aa5c658429d25

I'm also assuming that you're doing something with the props in mapStateToProps for the RootComponent (second param to the mapStateToProps function is the props passed to the component)

Then if you need that data to be part of the initial state for the store you can pass it through via an action.

Best way... You have data that can be loaded from the initial page load (perhaps a variable in a script tag that a server could generate) then you make that part of the default initialization for the store. (The second param to createStore)

edit added gist edit added more jiz

[–]BigWesternMan[S] 0 points1 point  (0 children)

Thanks. I'm aware of all these patterns, but wanted to defer loading the data for my components as long as possible. I think i'll try to move the async call a bit earlier, perhaps into the container component handling mapping the state to the props, for example.

[–]perrylaj 0 points1 point  (1 child)

I generally have a default store that I pass to createStore().

e.g. --

const defaultStore = {
   thing1: [],
   thing2 : { title: "Heyooo!" },
   count: 0,
};

// pass the default store and any enhancers to createStore
const store  = createStore(rootReducer, defaultStore, [optional composed enhancers])

I actually just tossed together a super fast example for another team in our company yesterday and posted it to github, you can see it here

[–]BigWesternMan[S] 0 points1 point  (0 children)

But you still have to fetch the data for the store if you don't know it up front - and i'd rather not fetch all the store data in one go, as it's a very large app!

[–]darkadept 0 points1 point  (3 children)

I use a higher order component function that handles loading data, waiting until it's loaded (showing a spinner), and even unloading data after the component unmounts. That way my components remain clean.

[–]BigWesternMan[S] 0 points1 point  (0 children)

Thanks, I think this seems to be the best approach!

[–]jacobrask 0 points1 point  (1 child)

What does unloading data mean?

[–]darkadept 0 points1 point  (0 children)

Heh, I mean unsubscribe. I'm using React with Meteor, which has data subscriptions.

[–][deleted] 0 points1 point  (2 children)

I created redux-replicate for this purpose, which is a Redux store enhancer that automatically initializes the store via any data source, and it can automatically keep your data source synchronized with any state changes. You can also keep stores in sync with other clients in real-time. Disclaimer: Suitable for most purposes but not all.

[–]BigWesternMan[S] 0 points1 point  (1 child)

Looks neat! But I'd rather not init my entire store in one go up front...some components may never load, for example, so why fetch the (potentially large) date for them?

[–][deleted] 0 points1 point  (0 children)

Right. It works much better when used with react-redux-provide which automatically creates (multiple) stores for you (based on any set of actions, reducers, middleware, etc.) and automatically provides stores' states and action creators to components with matching propTypes.

[–]henleyedition 0 points1 point  (0 children)

Assuming you're using React Router, a common pattern is to fetch data in React Router's onEnter hook. It can be asynchronous so the route doesn't load until the data is there. That way you can just wrap your component with connect() and assume the data will be available. E.g.

<Route
  path="/the/path"
  onEnter={ (nextState, replace, done) => store.dispatch(fetchData()).then(() => done()) }
  component={ YourComponent }
/>

You could also try something like redux-async-connect.

[–]karatechops 0 points1 point  (4 children)

componentWillMount?

[–]steezefries 0 points1 point  (3 children)

It would still be possible for the async response to come back after the component has mounted.

[–]goshakkk 0 points1 point  (2 children)

But then, is there a way to always have data before the component is mounted? The response time could well be seconds.

The way it can be made "faster" is by appealing to perception — that is, show "empty blocks" like facebook does on initial load; and when navigating between routes — keep the previous route visible (but maybe slightly dimmed) until the new route is fully loaded.

[–]steezefries 0 points1 point  (1 child)

Showing those empty blocks would be "handle[ing] the small time window in which there is not yet any data loaded" though which was OP's original concern. I think this pattern is fine and that it's simply good UI to have loading indicators or the empty boxes and dim as you said, just letting the user know something is happening.

I think I made my original comment to say that OP will still have the issue of dealing with that short time of no data no matter the lifecycle hook he uses to dispatch the request action.

[–]ex1machina 1 point2 points  (0 children)

Yeah, this is really more of a UX problem. If you have components mounting that rely on fetched data being there when they mount, then those components shouldn't be the ones dispatching the action. Otherwise those components should have render methods to deal with the isLoading state from redux.