Last active
October 28, 2016 21:46
-
-
Save ryanflorence/78ae1c7fd863812c388c10369e449971 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this `<Route>` component might make it possible for you to ~generally~ | |
// upgrade to React Router v4 w/o doing hardly anything to your app for the | |
// happy path stuff. | |
// | |
// This definitely won't work as-is, I haven't run this code, just banged it | |
// out when the thought occured to me that it might be possible. | |
const { func, object } = React.PropTypes | |
const Route = (route) => ( | |
<Match pattern={route.path} render={(props) => ( | |
route.children ? ( | |
<MatchWithRouteLifecycle route={route} {...props}> | |
<MatchGroup> | |
{React.Children.map(children, (child) => ( | |
<Route {...child.props}/> | |
))} | |
</MatchGroup> | |
</Component> | |
) : ( | |
<MatchWithRouteLifecycle route={route} {...props}/> | |
) | |
)}/> | |
) | |
class MatchWithRouteLifecycle extends React.Component { | |
static propTypes = { | |
route: { | |
component: func, | |
getComponent: func, | |
onEnter: func, | |
onChange: func, | |
onLeave: func, | |
components: object, // NOPE | |
getComponents: func, // NOPE | |
getChildRoutes: func // NOPE | |
}, | |
location: object, | |
path: string, | |
pattern: string | |
} | |
constructor(props) { | |
super(props) | |
this.state = { | |
prevProps: null, | |
needingToRunEnterHook: props.route.onEnter, | |
needingToGetComponent: props.route.getComponent, | |
AsyncComponent: null | |
} | |
} | |
componentDidMount() { | |
if (this.state.needingToRunEnterHook) { | |
this.runEnterHook() | |
} | |
if (this.state.needingToGetComponent) { | |
this.getComponent() | |
} | |
} | |
componentWillReceiveProps(nextProps) { | |
if (!locationsAreEqual(nextProps.location, this.props.location)) { | |
if (this.props.onChange) { | |
this.runChangeHook(nextHook) | |
} | |
} | |
} | |
componentWillUnmount() { | |
if (this.props.route.onLeave) { | |
this.runLeaveHook() | |
} | |
} | |
getComponent() { | |
this.props.route.getComponent((err, AsyncComponent) => { | |
this.setState({ AsyncComponent }) | |
}) | |
} | |
runLeaveHook() { | |
const prevState = {} | |
this.props.route.onLeave(prevState) | |
} | |
runEnterHook() { | |
const { onEnter } = this.props.route | |
const isAsync = onEnter.length === 3 | |
const nextState = {} | |
const replace = () => {} | |
if (isAsync) { | |
onEnter(nextState, replace, () => { | |
this.setState({ needingToRunEnterHook: false }) | |
}) | |
} else { | |
onEnter(nextState, replace) | |
this.setState({ needingToRunEnterHook: false }) | |
} | |
} | |
runChangeHook(nextProps) { | |
const { onChange } = this.props | |
const isAsync = onChange.length === 4 | |
const prevState = {} | |
const nextState = {} | |
const replace = () => {} | |
if (!isAsync) { | |
onChange(prevState, nextState, replace) | |
} else { | |
this.block(() => { | |
onChange(prevState, nextState, replace, this.unblock) | |
}) | |
} | |
} | |
block(cb) { | |
this.setState({ prevProps: this.props }, cb) | |
} | |
unblock() { | |
this.setState({ prevProps: null }) | |
} | |
render() { | |
if ( | |
this.state.needingToRunEnterHook || | |
this.state.needingToGetComponent | |
) { | |
return null | |
} else { | |
const props = this.state.prevProps ? | |
this.state.prevProps : this.props | |
const { route, params, location, children } = props | |
const Component = this.state.AsyncComponent || route.props.component | |
const v3Props = { ...route, params, location, children } | |
return <Component {...v3Props}/> | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment