簡易手寫react-router(函數(shù)式組件)

自己實(shí)現(xiàn)一個react-router

期望最簡單的使用效果

export default () => {
      return (
        <>
            <Link to="/a">菜單a</>
            <Link to="/b">菜單b</>
        </>
        <Router>
            <Route path="/a"><A /></Route>
            <Route path="/b"><B /></Route>
        </Router>
      )
}
Router一般分HashRouter和BrowserHistoryRouter,原理區(qū)別分別是對location.hash和history api的處理

先寫一些公用組件
// Link
const Link = ({ children }) => <a>children</a>

// Route 
const Route = () => {}

實(shí)現(xiàn)HashRouter

原理是在Link上綁定點(diǎn)擊更改hash值事件,利用瀏覽器監(jiān)聽hash值的變化做相應(yīng)的動作(渲染相應(yīng)組件),因?yàn)槭呛瘮?shù)組件,會用到useEffect,useState

// HashRouter
const HashRouter = ({ children }) => {
  const [hash, setHash] = useState(window.location.hash)
  // hash變更觸發(fā)
  const hashChange = e => {
      const { newURL } = e
      setHash(newURL.slice(newURL.indexOf('#')))
  }
  // 記得銷毀時要清除綁定
  useEffect(() => {
    window.addEventListener('hashchange', hashChange)
    return window.removeEventListener('hashchange', hashChange)
  }, [])
 // 為什么不用children遍歷,因?yàn)閏hildren有3種情況(1. 沒子組件會返回undefined 2.單個子組件返回一個對象 3.多個子組件返回數(shù)組),而React.Children會自行判斷,比較安全,當(dāng)然要多個null兜底,因?yàn)榉祷豼ndefined也會報錯
  return React.Children.map(children, child => {
      if(child.type.name === 'Route') {
        if(child.props.path === hash) {
            return child.props.children
        }
        return null
      }
      return child.props.children
  }) || null
}

相應(yīng)Link也要添加點(diǎn)擊邏輯

const Link = ({ to, children, handleClick }) => {
    const handleClick = () => window.location.hash = to
    <span onClick={handleClick}>{children}</span>
}
加一點(diǎn)排版

最簡單的功能就這樣完成了

...
<div id='menu'>
    <div><Link to='a'>a組件</Link></div<
</div>
<div id='container'>
    <HashRouter>
       <Route path='/a'><A /></Route>
    </HashRouter>
</div>

接著搞嵌套路由看看

export default () => <div style={containerStyle}>
  <div style={menuStyle}>
    <div><Link to='#/a'>a組件</Link></div>
    <div><Link to='#/b'>b組件</Link></div>
    <div><Link to='#/c'>C組件</Link></div>
  </div>
  <div style={contentStyle}>
    <HashRouter>
      <Route path="#/a"><A /></Route>
      <Route path="#/b"><B /></Route>
      <Route path="#/c"><C /></Route>
    </HashRouter>
  </div>

</div>

const C1 = () => <div>我是C1</div>
const C2 = () => <div>我是C2</div>

const C = () => (
  <div>
    <Link to='#/c/c1'>C1組件</Link>
    <Link to='#/c/c2'>C2組件</Link>
    <div style={contentStyle}>
      <h2>c下面的組件</h2>
      <HashRouter>
        <Route path="#/c/c1"><C1 /></Route>
        <Route path="#/c/c2"><C2 /></Route>
      </HashRouter>
    </div>
  </div>
)
#/c的效果
點(diǎn)擊C1

點(diǎn)擊C1或C2的Link,發(fā)現(xiàn)整個C都消失了,分析到因?yàn)楫?dāng)前hash應(yīng)當(dāng)是#/c/c1,而C組件本身對于要在#/c的時候才會渲染,用全等判斷自然不會渲染出來,子組件C1和C2肯定也不會出來


hash全等

將全等改成includes,發(fā)現(xiàn)效果出來了

    if (child.type.name === 'Route') {
      if (hash.includes(child.props.path)) {
        return child.props.children
      }
      return null
    }
改動后

待續(xù)更新BrowserRouter

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • React Router教程 React項(xiàng)目的可用的路由庫是React-Router,當(dāng)然這也是官方支持的。它也分...
    IT老馬閱讀 59,275評論 0 49
  • React Router教程 React項(xiàng)目的可用的路由庫是React-Router,當(dāng)然這也是官方支持的。它也分...
    張十七y閱讀 387評論 0 0
  • React Router教程 React項(xiàng)目的可用的路由庫是React-Router,當(dāng)然這也是官方支持的。它也分...
    __db84閱讀 758評論 0 0
  • 1. 后端路由與前端路由 多頁面應(yīng)用和后端路由在傳統(tǒng)的Web應(yīng)用中,瀏覽器根據(jù)地址欄的URL向服務(wù)器發(fā)送一個HTT...
    ImmortalSummer閱讀 1,031評論 0 1
  • React Router教程 React項(xiàng)目的可用的路由庫是React-Router,當(dāng)然這也是官方支持的。它也分...
    應(yīng)晨皓閱讀 486評論 0 0

友情鏈接更多精彩內(nèi)容