React-router 5.1介绍

1,820 阅读3分钟

react-router的核心是一个管理location的状态容器,它追踪location的变化并渲染不同的<Route>,还为开发者提供<Link>history API来更新locationreact-router 5.1中值得注意的是发布了一些hooks,如useParams, useHistory等,相比较于之前版本的组合组件,5.1版本提供了组合状态(state)和行为(behavior)的能力。下面简单介绍一个各个hooks

1. useParams

通过传入的组件的props.match或者<Route>render属性里传入的props.match, 如下

// before
function BlogPost({ match }) {
   let { slug } = match.params
   // ...
}
   
ReactDOM.render(
 <Router>
   <div>
     <Switch>
       {/* 方式一:Using the `component` prop */}
       <Route path="/blog/:slug" component={BlogPost} />

       {/* 方式二:Using the `render` prop */}
       <Route
         path="/posts/:slug"
         render={({ match }) => <BlogPost match={match} />}
       />
     </Switch>
   </div>
 </Router>,
 document.getElementById('root')
)

// after
function BlogPost() {
 // We can call useParams() here to get the params,
 // or in any child element as well!
 let { slug } = useParams()
 // ...
}

ReactDOM.render(
 <Router>
   <div>
     <Switch>
       {/* No weird props here, just use
           regular `children` elements! */}
       <Route path="/posts/:slug">
         <BlogPost />
       </Route>
     </Switch>
   </div>
 </Router>,
 document.getElementById('root')
)

方式一则需要router使用createElement(component)创建一个组件,而方式二则需要手动传递参数。 使用useParams之后,可以在BlogPost及其任意子组件中使用useParams,而且不需要手动传递参数

2. useLocation

useLocation返回当前的location对象,可以用于任何需要获取location的地方,下面的例子封装了一个统计pv的hook: usePageViews

import { Switch, useLocation } from 'react-router-dom'

function usePageViews() {
  let location = useLocation()

  useEffect(
    () => {
      ga.send(['pageview', location.pathname])
    },
    [location]
  )
}

function App() {
  usePageViews()
  return <Switch>{/* your routes here */}</Switch>
}use
3. useHistory

类似,5.1还提供了获取history的勾子(注:useHistory是为后面的useNavigate铺垫的 )

import { useHistory } from 'react-router-dom'

function BackButton({ children }) {
  let history = useHistory()
  return (
    <button type="button" onClick={() => history.goBack()}>
      {children}
    </button>
  )
}
4. useRouteMatch<{}>(path?: string | RouteProps | undefined): match<{}> | null

在一些场景中,我们可能会嵌套一层<Route>来获取match的数据,useRouteMatch则是可以直接获取匹配的url,包括了exact、strict、sensitive选项

// before
import { Route } from 'react-router-dom'

function App() {
  return (
    <div>
      {/* ... */}
      <Route
        path="/BLOG/:slug/"
        strict
        sensitive
        render={({ match }) => {
          return match ? <BlogPost match={match} /> : <NotFound />
        }}
      />
    </div>
  )
}

// after
import { useRouteMatch } from 'react-router-dom'

function App() {
  let match = useRouteMatch({
    path: '/BLOG/:slug/',
    strict: true,
    sensitive: true
  })

  return (
    <div>
      {/* ... */}
      {match ? <BlogPost match={match} /> : <NotFound />}
    </div>
  )
}

也可以直接使用

function Topics() {

  const match = useRouteMatch();
  
  if (match === null) {
    return <></>;
  }
  
  return (
    <div>
      <h2>Topics</h2>
      <ul>
        <li>
          <Link to={`${match.url}/components`}>Components</Link>
        </li>
        <li>
          <Link to={`${match.url}/props-v-state`}>Props v. State</Link>
        </li>
      </ul>

      <Switch>
        <Route path={`${match.path}/:topicId`}>
          <Topic />
        </Route>
        <Route path={match.path}>
          <h3>Please select a topic.</h3>
        </Route>
      </Switch>
    </div>
  );
}
function Topic() {
  const { topicId } = useParams();
  return <h3>Requested topic ID: {topicId}</h3>;
}
结语
  1. 推荐使用<Route children>替代<Route component><Route render>,这样可以使用jsx来组合元素,使用hooks来组合状态;
  2. 推荐使用hooks替代withRouter, 用useRouteMatch来代替<Switch>外的‘悬浮(仅为了获取匹配路由的信息)’的<Route>
  3. 虽然<Route component><Route render>以及withRouter在5.1中依然可用,但是未来很有可能会被废弃。

主要来源:reacttraining.com/blog/react-…