Component Rendering before Data fetch request in saga is completed
See original GitHub issueHi, I am using next.js in my project and have integrated redux, redux-saga & reselect with it. I am dispatching actions in async getIntialProps but the component renders before the saga request attached to respective action is completed.
- I have searched the issues of this repository and believe that this is not a duplicate.
Steps to Reproduce (for bugs)
- I made an action and attached saga listener with it
- I dispatched that action in async getInitialProps of pages/index.js
- It should have waited before going to render of pages/index.js
- However, the page rendered before the saga request got completed.
- In this way, page renders before the store is updated with newly fetched data.
Context
Your Environment
Tech | Version |
---|---|
next | ^4.1.4 |
node | >=6 |
OS | linux, windows |
browser | all |
etc |
The code for certain issue is as follows:
pages/index
class Home extends React.Component {
constructor(props) {
super(props);
}
static async getInitialProps({store}) {
await store.dispatch(getSettings())
await store.dispatch(getAboutUs())
console.log('Team Before',store.getState().home.Team)
await store.dispatch(getTeam())
console.log('Team After',store.getState().home.Team)
await store.dispatch(getServices())
await store.dispatch(getTestimonials())
await store.dispatch(getPortfolio())
await store.dispatch(getPortfolioSettings())
}
render() {
return (
<HomeContainer />
);
}
}
export default withReduxSaga(Home)
Home Container
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import Home from 'components/views/Home';
import { Router } from 'routes';
import Root from 'containers/Root'
import LinearLoader from 'components/widgets/Loaders/LinearProgressLoader'
import {
getSettings,
getAboutUs,
getTeam,
getServices,
getPortfolio,
getPortfolioSettings,
getTestimonials
} from './actions';
import {
selectSettings,
selectGetSettingsStatus,
selectAboutUs,
selectGetAboutUsStatus,
selectTeam,
selectGetTeamStatus,
selectServices,
selectGetServiceStatus,
selectTestimonials,
selectGetTestimonialsStatus,
selectPortfolios,
selectGetPortfoliosStatus,
selectPortfolioSettings,
selectGetPortfolioSettingsStatus
} from './selectors';
export class HomeContainer extends React.Component {
changeRoute = (route) => {
Router.replaceRoute(route);
}
render() {
console.log("Settings", this.props.Settings)
const { GetPortfolioSettingsStatus, GetSettingsStatus, GetAboutUsStatus, GetTeamStatus, GetServicesStatus, GetTestimonialStatus, GetPortfoliosStatus } = this.props;
if(GetSettingsStatus.get('loading')) {
return (
<LinearLoader />
);
}
return (
<div>
{!!this.props.Settings && <Root Settings={this.props.Settings} isHome SettingsStatus={GetSettingsStatus} >
<Home
Settings={this.props.Settings}
SettingsStatus={GetSettingsStatus}
changeRoute={this.changeRoute}
Team={this.props.Team}
TeamStatus={GetTeamStatus}
AboutUs={this.props.AboutUs}
AboutUsStatus={GetAboutUsStatus}
Services={this.props.Services}
ServicesStatus={GetServicesStatus}
Testimonials={this.props.Testimonials}
TestimonialStatus={GetTestimonialStatus}
Portfolios={this.props.Portfolios}
PortfoliosStatus={GetPortfoliosStatus}
PortfolioSettings={this.props.PortfolioSettings}
PortfolioSettingsStatus={GetPortfolioSettingsStatus}
/>
</Root>}
</div>
);
}
}
const mapDispatchToProps = (dispatch) => {
return {
onGetSettings: bindActionCreators(getSettings, dispatch),
onGetAboutUs: bindActionCreators(getAboutUs, dispatch),
onGetTeam: bindActionCreators(getTeam, dispatch),
onGetServices: bindActionCreators(getServices, dispatch),
onGetPortfolio: bindActionCreators(getPortfolio, dispatch),
onGetTestimonial: bindActionCreators(getTestimonials, dispatch),
onGetPortFolioSettings: bindActionCreators(getPortfolioSettings, dispatch)
}
}
const mapStateToProps = createStructuredSelector({
Settings: selectSettings(),
Team: selectTeam(),
AboutUs: selectAboutUs(),
Services: selectServices(),
Testimonials: selectTestimonials(),
Portfolios: selectPortfolios(),
PortfolioSettings: selectPortfolioSettings(),
GetSettingsStatus: selectGetSettingsStatus(),
GetTeamStatus: selectGetTeamStatus(),
GetAboutUsStatus: selectGetAboutUsStatus(),
GetServicesStatus: selectGetServiceStatus(),
GetTestimonialStatus: selectGetTestimonialsStatus(),
GetPortfoliosStatus: selectGetPortfoliosStatus(),
GetPortfolioSettingsStatus: selectGetPortfolioSettingsStatus()
});
export default connect(mapStateToProps, mapDispatchToProps)(HomeContainer)
Sagas
import es6promise from 'es6-promise'
import 'isomorphic-fetch'
import request from 'common/request'
import config from 'config/config'
import {
getSettingsSuccess,
getSettingsFail,
getAboutUsSuccess,
getAboutUsFail,
getServicesSuccess,
getServicesFail,
getPortfolioSuccess,
getPortfolioSettingsSuccess,
getPortfolioSettingsFail,
getPortfolioFail,
getTeamSuccess,
getTeamFail,
getTestimonialsSuccess,
getTestimonialsFail
} from './actions'
import {
GET_SETTINGS,
GET_ABOUT_US,
GET_SERVICES,
GET_PORTFOLIO,
GET_TEAM,
GET_TESTIMONIALS,
GET_PORTFOLIO_SETTINGS
} from './constants';
es6promise.polyfill()
function * getSettings () {
const settings = yield call(request, config.settings_type);
console.log('Settings Fetched: ', settings)
if(!settings) {
yield put(getSettingsFail('No Data Found'));
}
else if(!settings.err) {
yield put(getSettingsSuccess(settings[0]));
} else {
yield put(getSettingsFail(settings.err.reason));
}
}
function * getAboutUs () {
const aboutUs = yield call(request, config.about_us_type);
if(!aboutUs) {
yield put(getAboutUsFail('No Data Found'));
}
else if(!aboutUs.err) {
yield put(getAboutUsSuccess(aboutUs[0]));
} else {
yield put(getAboutUsFail(aboutUs.err.reason));
}
}
function * getServices () {
const services = yield call(request, config.services_type);
if(!services) {
yield put(getServicesFail('No Data Found'));
}
else if(!services.err) {
yield put(getServicesSuccess(services[0]));
} else {
yield put(getServicesFail(services.err.reason));
}
}
function * getPortfolio () {
const portfolio = yield call(request, config.portfolios_type);
if(!portfolio) {
yield put(getPortfolioFail('No Data Found'));
}
else if(!portfolio.err) {
yield put(getPortfolioSuccess(portfolio));
} else {
yield put(getPortfolioFail(portfolio.err.reason));
}
}
function * getPortfolioSettings () {
const portfolio_settings = yield call(request, config.portfolios_settings_type);
if(!portfolio_settings) {
yield put(getPortfolioSettingsFail('No Data Found'));
}
else if(!portfolio_settings.err) {
yield put(getPortfolioSettingsSuccess(portfolio_settings[0]));
} else {
yield put(getPortfolioSettingsFail(portfolio_settings.err.reason));
}
}
function * getTeam () {
const team = yield call(request, config.team_type);
// console.log('teams Fetched: ', team)
if(!team) {
yield put(getTeamFail('No Data Found'));
}
else if(!team.err) {
yield put(getTeamSuccess(team[0]));
} else {
yield put(getTeamFail(team.err.reason));
}
}
function * getTestimonials () {
const testimonials = yield call(request, config.testimonials_type);
if(!testimonials) {
yield put(getTestimonialsFail('No Data Found'));
}
else if(!testimonials.err) {
yield put(getTestimonialsSuccess(testimonials[0]));
} else {
yield put(getTestimonialsFail(testimonials.err.reason));
}
}
export function* homeSagas() {
yield fork(takeLatest, GET_SETTINGS, getSettings);
yield fork(takeLatest, GET_ABOUT_US, getAboutUs);
yield fork(takeLatest, GET_SERVICES, getServices);
yield fork(takeLatest, GET_PORTFOLIO, getPortfolio);
yield fork(takeLatest, GET_PORTFOLIO_SETTINGS, getPortfolioSettings);
yield fork(takeLatest, GET_TEAM, getTeam);
yield fork(takeLatest, GET_TESTIMONIALS, getTestimonials);
}
export default homeSagas;
Home Component
import ScrollableAnchor from 'react-scrollable-anchor'
import { Router } from 'routes';
import AboutUs from './AboutUs'
import Services from './Services'
import Team from './Team'
import Testimonials from './Testimonials'
import Portfolios from './Portfolio'
class Home extends React.Component {
constructor (props) {
super(props)
}
render() {
console.log('Teams available: ', this.props.Team)
return (
<div>
<div className="page-header" filter-color="orange">
{!!this.props.Settings && <div className="page-header-image" data-parallax="true" style={{backgroundColor: "grey", backgroundImage: `url(${this.props.Settings.getIn(['metadata','home_banner_image','url'])}`}} />}
<div className="container">
{
this.props.SettingsStatus.get('loaded') ?
<div className="content-center brand">
<img src={!!this.props.Settings ? this.props.Settings.getIn(['metadata','company_logo','url']): ''} alt={this.props.Settings.getIn(['metadata','agency_name'])} />
<h3>{!!this.props.Settings ? this.props.Settings.getIn(['metadata','punch_line']): 'Your Punch Line Here'}</h3>
</div>
:
<div className="content-center brand">
<h1> Loading ... </h1>
</div>
}
</div>
</div>
<div className="main">
{
this.props.AboutUsStatus.get('loading') ?
<div></div>
: this.props.AboutUsStatus.get('loaded') ?
<ScrollableAnchor id={'aboutUs'}>
<AboutUs aboutUs={this.props.AboutUs} changeRoute={this.props.changeRoute} />
</ScrollableAnchor>
: <div></div>
}
{
this.props.ServicesStatus.get('loading') ?
<div></div>
: this.props.ServicesStatus.get('loaded') ?
<ScrollableAnchor id={'services'}>
<Services services={this.props.Services} />
</ScrollableAnchor>
: <div></div>
}
{
this.props.TeamStatus.get('loading') ?
<div></div>
: this.props.TeamStatus.get('loaded') ?
<ScrollableAnchor id={'team'}>
<Team team={this.props.Team} />
</ScrollableAnchor>
: <div></div>
}
{
this.props.TestimonialStatus.get('loading') ?
<div></div>
: this.props.TestimonialStatus.get('loaded') ?
<ScrollableAnchor id={'testimonials'}>
<Testimonials testimonials={this.props.Testimonials} />
</ScrollableAnchor>
: <div></div>
}
{
this.props.PortfoliosStatus.get('loading') ?
<div></div>
: this.props.PortfoliosStatus.get('loaded') && this.props.PortfolioSettingsStatus.get('loaded') ?
<ScrollableAnchor id={'portfolio'}>
<Portfolios portfolios={this.props.Portfolios} settings={this.props.PortfolioSettings} changeRoute={this.props.changeRoute} />
</ScrollableAnchor>
: <div> </div>
}
</div>
</div>
);
}
}
export default (Home)
Issue Analytics
- State:
- Created 6 years ago
- Comments:5 (1 by maintainers)
Top Results From Across the Web
Component Rendering before Data fetch request in saga is ...
Hi All, I am trying to create a Landing page which fetches some data from API and then renders. The issue here is...
Read more >saga fetch data after component rendered - Stack Overflow
When you place function invocations directly in the function body they will be invoked any time react decides to "render" the component to...
Read more >How to fetch data in React with performance in mind
Shows a loading state until sidebar data is loaded first, renders sidebar, and keeps loading state until the data is finished in the...
Read more >Isomorphic Implementation of React | by Yudhajit Adhikary
Let's discuss in details how React Router Server Rendering happens ,First Server receives request and notes path,it creates history components and injects path, ......
Read more >React fetching data before rendering in 2020
The render gets compile error when data is not found · A child component render relies on data response from parent component ·...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@musaghauri how did you solve this issue?
You need to make sure saga is running, and monitor + waiting for saga.task is completed in ‘server’
https://github.com/zalabinc/nextjs-boilerpate/blob/master/app/utils/monitorSagas.js