Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hydration didn't complete before componentDidMount #72

Open
dstuff opened this issue Mar 27, 2019 · 1 comment
Open

Hydration didn't complete before componentDidMount #72

dstuff opened this issue Mar 27, 2019 · 1 comment

Comments

@dstuff
Copy link

dstuff commented Mar 27, 2019

I've got an empty store on componentDidMount so I can't render data on component loading. As I can see via logs store hydrated just after the component was mounted.

I've tried to implement solution from #38 on my root component (App.js) but if user not on index page then componentDidMount with hydration didn't trigger.

import {store} from '../../state';

import Header from '../header';
import Footer from '../footer';
import ErrorBoundry from '../error-boundry';

import './app.css';
import MainPage from '../main-page';
import LoginPage from '../login-page';
import AccountPage from '../account-page';

import {create} from 'mobx-persist';

const hydrate = create({
  storage: localStorage,
  jsonify: true,
});

@observer
class App extends Component {

  async componentDidMount() {
    await hydrate('store', store);
    console.log('Mounted index page');
  }

  SearchPage = () => <h2>Search Page</h2>;
  AddListingPage = () => <h2>Add Listing Page</h2>;

  render() {
    return (
      <Provider store={store}>
        <ErrorBoundry>
          <Router>
            <div className="app-container">
              <Header />
               <div className="content-wrapper">
                 <Route path="/" exact component={MainPage}/>
                 <Route path="/search" component={this.SearchPage}/>
                 <Route path="/account" component={AccountPage}/>
                 <Route path="/login" component={LoginPage}/>
                 <Route path="/add-listing" component={this.AddListingPage}/>
               </div>
              <Footer />
            </div>
          </Router>
        </ErrorBoundry>
      </Provider>
    );
  }
}

For example, in AccountPage store is empty on componentDidMount. Only way I can check if user logged-in is adding check to componentDidUpdate.

...

@inject('store')
@withRouter
@observer
class AccountPage extends Component {

  state = {
    user: Object.assign({}, this.props.store.user.user),
  };

  componentDidMount() {
    console.log('Account', this.props.store.user);
  }

  componentDidUpdate() {
    const {store, history} = this.props;
    if(!store.auth.isLogged) {
      history.push('/login');
    }
  }

  ...
  render() {
  <div>
    {this.props.store.user.user.firstName}
    {this.props.store.auth.isLogged}
  </div>
}
}

Any suggestions on how to get a hydrated store before component will be mounted on any page? I'm using react-router

@YashGadle
Copy link

YashGadle commented Apr 11, 2019

Hey, I had a similar issue, where my APIs were getting called from cDM while the hydration was not complete. hence some empty headers and params were being passed. So what I did was, I created a component called PersistStore that had the responsibility of hydrating all my stores and after all of them were hydrated only then I would render my main app. Here is the code.

const rootStore = new RootStore();
constructor(props: Props) {
    super(props);

    const p1 = create()('albumsModel', rootStore.albumsModel);
    const p2 = create()('userModel', rootStore.userModel);
    const p3 = create()('imagesModel', rootStore.imagesModel);
    const p4 = create()('contextStore', rootStore.context);
    
    Promise.all([p1, p2, p3, p4])
	.then(() => {
              this.setHydration(true);
	})
	.catch(err => {
		this.setHydration(true);
		throw err;
	});
}

@action('Set Hydration flag')
setHydration(x: boolean) {
	this.isHydrationComplete = x;
}

render() {
	if (!this.isHydrationComplete) return null;
	return this.props.render(rootStore.getStores());
}

And this would be a wrapper for your main app. I am using render props pattern but you could easily use hooks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants