react-router实现

83 阅读1分钟

Router包括BrowserRouter HashRouter MemoryRouter

BrowserRouter使用HTML5提供的history API(pushState.replaceState和popstate)来保持UI和URL的同步

HashRouter使用URL的hash的部分(即window.location.hash)来保持UI和URL的同步

app.js

import React from "react";
import {BrowserRouter as Router} from "./kreact-router-dom/BrowserRouter";
import Route from "./k-react-router-dom/Route";
import Link from "./k-react-router-dom/Link";
import Switch from "./k-react-routerdom/Switch";
import HomePage from "./pages/HomePage";
import UserPage from "./pages/UserPage";
import LoginPage from "./pages/LoginPage";
import PrivateRoute from "./pages/PrivateRoute";
function App() {
return (
<div className="App">
  <Router>
      <Link to="/">⾸首⻚页</Link>
      <Link to="/user">
         ⽤用户中⼼心
      </Link>
      <Link to="/login">登录</Link>
     <Link to="/children">children</Link>
     <Link to="/render">render</Link>
     <Link to="/search/123">搜索-动态路路由</Link>
      {/* <Switch location={{pathname: "/"}}>*/}
    <Switch>
     <Route exact path="/" component={HomePage} />
     {/* <Route path="/user" component={UserPage} /> */}
      <PrivateRoute path="/user" component={UserPage} />
      <Route path="/login" component={LoginPage} />
      <Route path="/children" children={()=> <div>children</div>} />
      <Route path="/render" render={() =><div>render</div>} />
      <Route path="/search/:id" component={searchComponent} />
   </Switch>
 </Router>
</div>
);
};


export default App;
function searchComponent(props) {
  const {id} = props.match.params;
  console.log("searchComponent-props", props);
   //sy-log
  return (
   <div>
      <div>searchComponent-{id}</div>
     <Link to={"/search/" + id + "/detail"}>详情-嵌套路路由</Link>
     <Route path={"/search/:id/detail"} component={DetailComponent} />
   </div>
   );
}

  function DetailComponent(props) {
   const {id} = props.match.params;
   console.log("DetailComponent-props", props);
  //sy-log
   return <div>DetailComponent</div>;
}

实现BrowserRouter

import React, {Component} from "react";
import {createBrowserHistory} from "history";
import matchPath from "./matchPath";
const RouterConetext=React.createContext();
export class BrowserRouter extends Component{
   constructor(props){
     super(props)
     this.state={};
     this.histroy=createBrowserHistory();
     this.state={
        location:this.history.location;
      }
      this.unlisten=this.history.listen(location=>{
         this.setState({
           location:location
         })
       })
   }
   componentWillUnmount(){
     if(this.unlisten){
       this.unlisten();
      }
   }
   render(){
     <RouterContext.Provider
      children={this.props.children}
      value={{history:this.history,location:this.state.location}}
     
     />
   }
}

实现Route

路由配置 匹配检测 内容渲染

export  class Route extends Component{
   render(){
     return(
       <RouterContext.Consumer>
         {context=>{
            const  location=this.props.location||context.location;
            const match=this.props.computedMatch
                        ?this.props.computedMatch
                        :this.props.path
                        ?matchPath(location.pathname,this.props)
                        :context.match;
            const props={
             ...context,
             location,
             match
            };
            let {path,children,component,render}=this.props;
            return(
              <RouterContext.Provider value={props}>
                 {
                   match
                     ?children
                       ?typeof children==="function"
                         ?children(props)
                         :children
                       :component
                          ?React.createElement(component,props)
                          :render
                            ?render(props)
                            :null
                    :typeof children==="function"
                       ?children(props)
                       :null
                 }
              </RouteContext.Propvider>
            )
                        
         }
         
          }
       </RouterContext.Consumer>
      )
    }
}

实现Link

export class Link extends Component{
  static contextType=RouterContext;
  handleClick=event=>{
    event.preventDefault();
    this.context.history.push(this.props.to)
    
  }
  render(){
    const {to}=this.props;
    return (
      <a href={to} onClick={this.hnadleClick}>
        {this.props.children}
      </a>
    )
  }
 
}

实现Switch

export class Switch extends Component{
  render(){
    <RouterContext.Consumer>
      { context=>{
          loaction=context.location;
          let element,match;
          React.children.forEach(this.props.children,child=>{
          if(match==null && React.isValidElement(child)){
            element=child;
            const path=children.props.path;
            match=path?matchPath(location.pathname,{...child.props,path}:context.match
            
            }
      
          })
          return match?Reat.cloneElement(element,{location}):null;
        }
      
      }
    
    </RouterContext.Consumer>
  }
}

实现Redirect

   import React, {Component} from "react";
import {RouterContext} from "./RouterContext";
 export default class Redirect extends component{
   render(){
      return (
        <RouterContext.Consumer>
          {
            context=>{
              const {history}=this.conetxt;
              const {to} =this.props;
              return <LifeCyle onMount={()=>history.replace(to)}/>
              
            }
          }  
        
        </RouterContext.Consumer>
      )
   }
 }
 class LifeCyle extends Component{
   componentDidMount(){
     if(this.props.onMount){
       this.props.onMount.call(this,this);
     }
   }
   render(){
     return null;
   }
 }