Skip to content

Instantly share code, notes, and snippets.

@dleavitt
Last active June 24, 2017 21:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dleavitt/518b624d49c6bff7c2d7ee2782607ce3 to your computer and use it in GitHub Desktop.
Save dleavitt/518b624d49c6bff7c2d7ee2782607ce3 to your computer and use it in GitHub Desktop.
mobx-react-router repro code
import React from 'react'
import { observer } from 'mobx-react'
import { RouteComponentProps, withRouter } from 'react-router-dom'
type WithRouterProps<P> = React.SFC<RouteComponentProps<any> & P>
| React.ComponentClass<RouteComponentProps<any> & P>
// makes the component an observer and also makes sure it rerenders on routing
// changes
export default function routeable<P>(Component: React.ComponentClass<P>) {
class RouteableObserver extends React.Component<P, any> {
render() {
return React.createElement(Component, this.props)
}
}
return withRouter(
observer(RouteableObserver) as WithRouterProps<P>
) as typeof RouteableObserver
}
// https://codepen.io/pygmael/pen/BZwyGG
import React from 'react'
import { render } from 'react-dom'
import { observable } from 'mobx'
import { Provider, observer, inject } from 'mobx-react'
import { Router, Route, RouteComponentProps, NavLink, withRouter } from 'react-router-dom'
import { RouterStore, syncHistoryWithStore } from 'mobx-react-router'
import { History, createBrowserHistory } from 'history'
class DummyStore {
@observable maybe: boolean = true
}
const routerStore = new RouterStore()
const dummyStore = new DummyStore()
const history = syncHistoryWithStore(createBrowserHistory(), routerStore)
history.subscribe((location, action) => console.log(location.pathname))
class Root extends React.Component<{}, {}> {
render() {
return (
<Provider routing={routerStore} dummy={dummyStore}>
<Router history={routerStore.history}>
<Route component={Parent} />
</Router>
</Provider>
)
}
}
@inject('dummy')
@observer
class Parent extends React.Component<RouteComponentProps<{}> & { dummy?: DummyStore }, {}> {
render() {
// This component is directly under the route so its NavLinks, etc always work
return (
<div style={{ border: '1px white solid', margin: '8px', padding: '12px' }}>
Parent
<br />
<NavLink to="/sandbox" activeStyle={{ color: 'red', textDecoration: 'none' }}>Sandbox</NavLink>
{' '} | {' '}
<NavLink to="/styleguide" activeStyle={{ color: 'red', textDecoration: 'none' }}>Styleguide</NavLink>
{' '}
<button type="button" onClick={() => this.props.dummy!.maybe = !this.props.dummy!.maybe}>
Toggle {this.props.dummy!.maybe ? 'TRUE' : 'FALSE'}
</button>
<Inter />
</div>
)
}
}
// remove this observer annotation and routing works
// it doesn't seem to break store injection on the child either
@observer
class Inter extends React.Component<{}, {}> {
render() {
return (
<div style={{ border: '1px green solid', padding: '12px' }}>
Inter
<Child />
</div>
)
}
}
@inject('dummy', 'routing')
@observer
class Child extends React.Component<{dummy?: DummyStore, routing?: RouterStore}, {}> {
render() {
// The store is updated, but those updates don't make it to the Route/NavLink components
return (
<div style={{ border: '1px red solid', padding: '12px' }}>
Child<br />
<NavLink to="/sandbox" activeStyle={{ color: 'red', textDecoration: 'none' }}>Sandbox</NavLink>
{' '} | {' '}
<NavLink to="/styleguide" activeStyle={{ color: 'red', textDecoration: 'none' }}>Styleguide</NavLink>
<Route path="/sandbox" component={SandboxLabel} />
<Route path="/styleguide" component={StyleguideLabel} />
Toggle: {this.props.dummy!.maybe ? 'TRUE' : 'FALSE'}
<br />
From RouterStore: {this.props.routing!.location!.pathname}
</div>
)
}
}
const SandboxLabel = (props: RouteComponentProps<{}>) => <div>SandboxLabel</div>
const StyleguideLabel = (props: RouteComponentProps<{}>) => <div>StyleguideLabel</div>
render(<Root />, document.getElementById('root'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment