mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
examples/with-mobx : Fix and simplify (#5537)
I spent far too much time fiddling with this example project before realizing it contained a bug in the store initialization logic and it was a bit more complex than it needed to be. * The custom server was not needed * The store-initialization did effectively the same thing twice for no reason * And wrapping MyApp component in a HOC was wholly unnecessary indirection My changes are split into four discrete commits for clarity.
This commit is contained in:
parent
a09ca535c3
commit
420f74c867
|
@ -1,50 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import {initializeStore} from '../store'
|
|
||||||
|
|
||||||
const isServer = typeof window === 'undefined'
|
|
||||||
const __NEXT_MOBX_STORE__ = '__NEXT_MOBX_STORE__'
|
|
||||||
|
|
||||||
function getOrCreateStore(initialState) {
|
|
||||||
// Always make a new store if server, otherwise state is shared between requests
|
|
||||||
if (isServer) {
|
|
||||||
return initializeStore(initialState)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create store if unavailable on the client and set it on the window object
|
|
||||||
if (!window[__NEXT_MOBX_STORE__]) {
|
|
||||||
window[__NEXT_MOBX_STORE__] = initializeStore(initialState)
|
|
||||||
}
|
|
||||||
return window[__NEXT_MOBX_STORE__]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (App) => {
|
|
||||||
return class AppWithMobx extends React.Component {
|
|
||||||
static async getInitialProps (appContext) {
|
|
||||||
// Get or Create the store with `undefined` as initialState
|
|
||||||
// This allows you to set a custom default initialState
|
|
||||||
const mobxStore = getOrCreateStore()
|
|
||||||
|
|
||||||
// Provide the store to getInitialProps of pages
|
|
||||||
appContext.ctx.mobxStore = mobxStore
|
|
||||||
|
|
||||||
let appProps = {}
|
|
||||||
if (typeof App.getInitialProps === 'function') {
|
|
||||||
appProps = await App.getInitialProps.call(App, appContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...appProps,
|
|
||||||
initialMobxState: mobxStore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
this.mobxStore = getOrCreateStore(props.initialMobxState)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <App {...this.props} mobxStore={this.mobxStore} />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,9 +2,9 @@
|
||||||
"name": "with-mobx",
|
"name": "with-mobx",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node server.js",
|
"dev": "next",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "NODE_ENV=production node server.js"
|
"start": "next start"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mobx": "^2.7.0",
|
"mobx": "^2.7.0",
|
||||||
|
|
|
@ -1,19 +1,38 @@
|
||||||
import App, {Container} from 'next/app'
|
import App, {Container} from 'next/app'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import withMobxStore from '../lib/with-mobx-store'
|
import { initializeStore } from '../store'
|
||||||
import { Provider } from 'mobx-react'
|
import { Provider } from 'mobx-react'
|
||||||
|
|
||||||
class MyApp extends App {
|
class MyMobxApp extends App {
|
||||||
|
static async getInitialProps(appContext) {
|
||||||
|
// Get or Create the store with `undefined` as initialState
|
||||||
|
// This allows you to set a custom default initialState
|
||||||
|
const mobxStore = initializeStore()
|
||||||
|
// Provide the store to getInitialProps of pages
|
||||||
|
appContext.ctx.mobxStore = mobxStore
|
||||||
|
|
||||||
|
let appProps = await App.getInitialProps(appContext)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...appProps,
|
||||||
|
initialMobxState: mobxStore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.mobxStore = initializeStore(props.initialMobxState)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {Component, pageProps, mobxStore} = this.props
|
const { Component, pageProps } = this.props
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Provider store={mobxStore}>
|
<Provider store={this.mobxStore}>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</Provider>
|
</Provider>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export default MyMobxApp
|
||||||
export default withMobxStore(MyApp)
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
const port = parseInt(process.env.PORT, 10) || 3000
|
|
||||||
const dev = process.env.NODE_ENV !== 'production'
|
|
||||||
|
|
||||||
const { createServer } = require('http')
|
|
||||||
const { parse } = require('url')
|
|
||||||
const next = require('next')
|
|
||||||
const mobxReact = require('mobx-react')
|
|
||||||
const app = next({ dev })
|
|
||||||
const handle = app.getRequestHandler()
|
|
||||||
|
|
||||||
mobxReact.useStaticRendering(true)
|
|
||||||
|
|
||||||
app.prepare().then(() => {
|
|
||||||
createServer((req, res) => {
|
|
||||||
const parsedUrl = parse(req.url, true)
|
|
||||||
handle(req, res, parsedUrl)
|
|
||||||
}).listen(port, err => {
|
|
||||||
if (err) throw err
|
|
||||||
console.log(`> Ready on http://localhost:${port}`)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,13 +1,16 @@
|
||||||
import { action, observable } from 'mobx'
|
import { action, observable } from 'mobx'
|
||||||
|
import { useStaticRendering } from 'mobx-react'
|
||||||
|
|
||||||
let store = null
|
const isServer = typeof window === 'undefined'
|
||||||
|
useStaticRendering(isServer)
|
||||||
|
|
||||||
class Store {
|
class Store {
|
||||||
@observable lastUpdate = 0
|
@observable lastUpdate = 0
|
||||||
@observable light = false
|
@observable light = false
|
||||||
|
|
||||||
constructor (isServer, lastUpdate) {
|
constructor (isServer, initialData = {}) {
|
||||||
this.lastUpdate = lastUpdate
|
this.lastUpdate = initialData.lastUpdate != null ? initialData.lastUpdate : Date.now()
|
||||||
|
this.light = !!initialData.light
|
||||||
}
|
}
|
||||||
|
|
||||||
@action start = () => {
|
@action start = () => {
|
||||||
|
@ -20,13 +23,15 @@ class Store {
|
||||||
stop = () => clearInterval(this.timer)
|
stop = () => clearInterval(this.timer)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initializeStore (isServer, lastUpdate = Date.now()) {
|
|
||||||
|
let store = null
|
||||||
|
export function initializeStore (initialData) {
|
||||||
|
// Always make a new store if server, otherwise state is shared between requests
|
||||||
if (isServer) {
|
if (isServer) {
|
||||||
return new Store(isServer, lastUpdate)
|
return new Store(isServer, initialData)
|
||||||
} else {
|
}
|
||||||
if (store === null) {
|
if (store === null) {
|
||||||
store = new Store(isServer, lastUpdate)
|
store = new Store(isServer, initialData)
|
||||||
}
|
}
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue