Skip to content

Instantly share code, notes, and snippets.

@mohsen1
Created July 31, 2017 21:20
Show Gist options
  • Save mohsen1/d3ab99ade3a7b649e2c2f212a0b4b5a9 to your computer and use it in GitHub Desktop.
Save mohsen1/d3ab99ade3a7b649e2c2f212a0b4b5a9 to your computer and use it in GitHub Desktop.
How to hydrate stores in the server with MobX
import * as React from 'react';
import { computed } from 'mobx';
import { inject, observer, Provider } from 'mobx-react';
import { fromPromise } from 'mobx-utils';
import {StaticRouter} from 'react-router-dom';
import { Request, Response } from 'express';
import * as ReactDOM from 'react-dom/server';
interface Item {
weight: number;
}
class HydratableStore {
__hydration_promises: Promise<any>[] = [];
waitForHydration() {
return Promise.all(this.__hydration_promises);
}
}
class Store extends HydratableStore {
itemsPromise?: Promise<Item>;
@hydratable @computed get item() {
if (!this.itemsPromise) {
this.itemsPromise = fetch('/item').then(res => res.json());
}
return this.itemsPromise;
}
toString() {
}
}
@inject('store')
@observer
class ItemComp extends React.Component<{store?: Store}, {item: Item}> {
state = { item: null }
componentWillMount() {
this.props.store.item.then(item => {
this.setState({ item });
});
}
render() {
return <div>{this.state.item}</div>
}
}
const App = () => <ItemComp />
// in server
export async function render(req: Request, res: Response) {
const store = new Store();
const app = (
<Provider store={store}>
<StaticRouter location={req.url}>
<App />
</StaticRouter>
</Provider>
)
await store.waitForHydration();
res.send(`
<body>
<div id="root">${ReactDOM.renderToString(app)}</div>
<script>window.__store_state__ = ${serialize(store)}</script>
</body>
`);
}
function hydratable() {
return function() {
// grab the returned promise of the getter function and push it to __hydration_promises
// of store instance. This requires store to inherit from HydratableStore
// TODO
}
}
function serialize(store: Store) {
return ''
}
@elado
Copy link

elado commented Aug 1, 2017

        this.props.store.item.then(item => {
            this.setState({ item });
        });

how do you react on store.item changes? keeping it in state won't re-render when there are property changes (I think, might be wrong) and definitely won't re-render when store.item becomes null (as a result of another operation)

I think we should stick to read store directly or read mobx objects from props, not state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment