Skip to content

Instantly share code, notes, and snippets.

@lxynox
Last active September 12, 2019 08:09
Show Gist options
  • Save lxynox/ecb9b071a60b3f443da8240135635f57 to your computer and use it in GitHub Desktop.
Save lxynox/ecb9b071a60b3f443da8240135635f57 to your computer and use it in GitHub Desktop.
simple react router

Top level Components handles client-side navigation state (HTML5 history api) transition

History API (State - source of truth)

Link (Dispatcher)

class Link extends React.PureComponent {
  static propTypes = {
    to: PropTypes.string,
    replace: PropTypes.bool,
    children: PropTypes.object
  }
  
  handleClick = (event) => {
    event.preventDefault()
    const { replace, to } = this.props
    if (!replace)
      history.pushState({ to }, 'push', to)
    else
      history.replaceState({ to }, 'replace', to)
  }
  
  render() {
    return (
      <a href={this.props.to} onClick={this.handleClick}>
        {this.props.children}
      </a>
    )
  }
}

Router (Subscriber)

class Router extends React.Component{
  static propTypes = {
    history: PropTypes.object,
    children: PropTypes.object
  }
  
  constructor(props) {
    super(props)
    this.state = {
      match: {}
    }
  }
 
  componentWillMount() {
    this.unlisten = history.listen(() => {
      this.setState({
        match: {
          path: '',
          url: '',
          params: {},
          isExact: pathname === '/'
        }
      })
    })
  }
  
  componentWillUnmount() {
    this.unlisten()   
  }
  
  render() {
    const { children } = this.props
    return children ? children : null
  }
}

Route (HOC - path matching handdler)

class Route extends React.Component {
  static propTypes = {
    path: PropTypes.string,
    component: PropTypes.func, // three different rendering props
    render: PropTypes.func,
    children: PropTypes.object
  }
  
  constructor(props) {
    super(props)
    this.state = {
      match: false
    }
  }
  
  render() {
    const { match } = this.state
    const {
      component,
      render,
      children
    } = this.props
    
    const props = { history, location, match }
    
    if (component)
      return match ? React.createElement(component, props) : null
    if (render)
      return match ? render(props) : null
    if (typeof children === 'function')
      return children(props) // children render anyway w/o **match**
    return React.Children.only(children)
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment