react-redux-starter-kit
react-redux-starter-kit copied to clipboard
Put rendering on-hold until initial fetch is done
Hi @davezuko , I have a question on how to postpone child-rendering until a certain condition is met.
For example: Let's say I have an "app" component. And on top of that, I have 2 modules inside my route: /products -> accessing Product module. /users -> accessing User module.
The app will render the children component based on its route. but, on "app" component, there's a necessary API that should be called first before rendering its children component.
App/Component.js
class CoreLayout extends React.Component {
componentWillMount() {
this.props.fetchInitialSettings();
}
render() {
return (
<div>
<Header />
{this.props.children}
<Footer />
</div>
);
}
}
If the user access '/' directly, then it should not be a problem. but if the user access '/products' directly, can we ensure the "this.props.fetchInitialSettings();" is done first on the "app" then continue rendering the children component?
I've tried to modified App/Component.js to look like this:
class CoreLayout extends React.Component {
componentWillMount() {
this.props.fetchInitialSettings();
}
componentDidMount() {
this.node = ReactDOM.findDOMNode(this.refs.container);
this.renderContent();
}
componentWillReceiveProps(newProps) {
this.renderContent(newProps);
}
renderContent(props) {
props = props || this.props;
if (props.firstLoadDone) {
ReactDOM.render(<Provider store={props.store}>{props.children}</Provider>, this.node);
}
else {
ReactDOM.render(<div />, this.node);
}
}
render() {
return (
<div>
<Header />
<div className='main' ref='container'></div>
<Footer />
</div>
);
}
}
But I'm not sure wether this is the right approach. I used a flag in the state, "firstLoadDone", to keep track wether fetchInitialSettings is done or not. And only after it's done, componentWillReceiveProps will be called, and then I render the children component.
However, it doesn't feel right. For example, I have to wrap the children inside "Provider" again, together with the "store" and pass down the original "store" to children component, otherwise, the children component will loose their access to original store.
And I'd like to use this approach for deeper route, for example: the user access /products/31 directly. Meaning:
- Render app component
- Wait for necessary API for app is done
- if done, render product component
- Wait for necessary API for product is done
- if done, render product-detail component
- done
Thanks in advance
Regards, Riki
Did you ever work this out? I have a similar problem. I need to load a few json files before anything renders. It works fine in development, but when I run compile and put it on a server, the app crashes on init because the components are expecting data. I'm at my wits end, at this point.
One can use Redux here and:
-
Set up a
reducer
containing an initialstate
of{ ... loading: true ... }
, issue anaction
of your choice in your a component'scomponentDidMount()
to fetch the prerequisites (assuming an async flow so most probably athunk
along with other async Redux middlewares, e.g. redux-simple-promise). -
Set up the
render()
method like such:
// context: Within a 'higher-order enough' `React.Component`
render() {
// Don't forget to `connect` the `component` to the Redux `store` yada yada
const { loading } = this.props;
return (
!loading &&
<MyComponent />
);
}
This is a React idiom to basically render nothing (null
is also used) if the underlying 'precondition' (in this case, the loading
flag) fails/is not met.
- Handle the response in the associated
reducer
(passing it down as aprop
) in case of success/failure (redux-simple-promise
action types are conventionally calledMyActionSuccess
and*Failure
or so). A*Success
response would move/take the state to{ ... loading: false ... }
.
Thus, the MyComponent
component will be render
-ed only if loading
is false
.
This !loading && trick is very nice!
So If I want to avoid doing this in all my controllers.. suppose I want to have always my nav bar in the header which should be loaded before any body component. Is wrapping the "body components" inside a component following the loading:false pattern is the way to go?
@enkil2003: Yes, that would be the way to go, my use case involved having a <Footer>
type of component and other 'main' components (the body
type of components, yes), which would only get rendered if loading
was false
.