上节课我们介绍了嵌套路由,有了嵌套路由我们就可以来完成一些更加复杂的页面了,这节课呢我们来介绍一点新的东西。不知道大家还记不记得我们之前说一般组件和路由组件的最大的区别就是,组件接收到的props不同,一般组件是我传什么,就收到什么,而路由组件是路由组件会固定传入三个属性进去。这节课我们就来说一说这个方面的东西。

回顾

当然在,开始这节课的内容之前,我们先来对上节课的内容来做一个简单的回顾。

  • 不要轻易开启严格匹配,否则可能会无法匹配子级路由
  • 嵌套路由就是多级路由,刻在某一路由下再包含其他路由
  • 嵌套路由的路径要加上父路由的路径
  • 路由匹配是按照注册顺序逐层注册匹配的

以上便是上节课的主要要点,接下来我们开始我们这节课的内容。

需求效果

我们首先先来回忆一下上节课中,我们案例一直是在拿News来举例。可能大家没注意到我们的Message的列表里面都是一个个的链接。我们现在要的效果是什么呢?就是当我们点击其中的链接,我们要在页面下方展示这个链接中的详情。

image-20220117112302655

就和图中展示的内容类似,我们点击message001然后就在页面下方展示这条message的详情内容。而且浏览器地址路径也要变成/home/message/1

分析

就刚才的效果,大家有没有觉得我们又多出来一个导航区和展示区?只不过这次导航区不再是导航栏,而是一个链接列表了。那么从层级上来是,这一块是不是就应该是一个三级路由了?还有一点,我们这个展示区的结构其实都是一样的,只不过我们点击的时候展示了不同的内容,那么我们是不是就不用抽成三个组件来写了?这样我们可以省掉很多代码,不然如果这里如果有 10 条messsage或者说更多的话我们就得写很多小组件,这种就造成了很严重的代码冗余。

那么我们将这个展示区值作为一个公用的组件就会很方便,里面要展示的结构是固定的,那么内容直接通过props传进去就好了啊。但是问题来了。这个组件是不是也要根据路由来管理?因为我们都是根据浏览器地址的不同路径来控制不同内容的展示的,所以说这也还是一个路由组件。那么路由组件我们怎么给他传参数?

一般组件我们可以通过手动在组件标签中来写标签属性传入props,可是路由组件呢?路由组件我们没有写组件标签啊,我们也没法手动传props啊,路由组件收到的是路由自动传进去的三个固定属性啊。那么我们应该怎么处理呢?先别着急,我们先把能实现的给实现掉。

导航区

我们也别把这一块写死了,我们用state来生成这段导航区

export default class Message extends Component {
  state = { 
    messageArr:[
      { id:1, title:"message001" },
      { id:2, title:"message002" },
      { id:3, title:"message003" },
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <ul>
        {messageArr.map(msg=><li key={msg.id}><a href="/#">{msg.title}</a></li>)}
      </ul>
    )
  }
}

来看代码,我们初始化了statestate中有idtitle,那么遍历一下生成相应的a标签,但是往哪咱还没想好先放着。这样我们来看一下效果:

image-20220117114803925

展示区

现在我们的导航区已经完成了,那么展示区我们说了是一个固定结构,我们单独抽成一个组件,就叫Details吧,我们来先把组件的结构给实现出来。

export default class Details extends Component {
  render() {
    return (
      <ul>
        <li>ID: ???</li>
        <li>TITLE: ???</li>
        <li>CONTENT: ???</li>
      </ul>
    )
  }
}

因为我们还不知道要展示什么,所以先用问号来代替,那么我们在什么事才会展示Details组件?是不是在我们点击了Message中的导航区才会展示?那么我们就要在Message中来引入Details,然后来看一下展示效果:

image-20220117115637899

设置路由

展示是不是正常?但是我们这么展示对吗?当然不对啊,我们都没有点怎么可以展示呢?所以说我们是不是就要把每条消息的<a>改成路由链接?那么我来问大家,这里我们需要用NavLink吗?是不是不需要?我们没有要高亮的需求。所以直接用Link就行了

export default class Message extends Component {
  state = {
    messageArr: [
      { id: 1, title: "message001" },
      { id: 2, title: "message002" },
      { id: 3, title: "message003" },
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {messageArr.map(
            msg => <li key={msg.id}>
              <Link to="/home/message/detials">{msg.title}</Link>
            </li>
          )}
        </ul>
        <Route path="/home/message/detials" component={Details} />
      </div>
    )
  }
}

我们先来看一下代码,我们把<a>改成了<Link>,既然我们设置了路由链接,那么我们是不是就要注册路由?因为是三级路由所以我们路由链接或者是注册路由时候,路径我们都得把/home/message都给加上。然后现在我们来看一下效果:

image-20220117120712058

没有点击的时候就没有任何展示了。,当我们点击一下:

image-20220117120742953

点击之后,我们就可以看到我们的Details组件就正常展示出来了。但是我们的需求并不是这样,我们要展示的是每条消息都要有内容。那么我们就要把每条消息的信息传给Detatils组件。而且路径是消息的id。那么我们应该如何处理呢?

携带params参数

我们上面说的那么热闹,但是参数传不进去都是白瞎,那么我们接下来来讲一下如何给路由组件传参,我们先来讲最简单那的一种,就是params参数。

提到params参数大家应该有过一点了解,我们在学习ajax的时候,是不是学过ajax请求可以携带 3 种参数?第一种是query参数,第二种是params参数,第三种是body参数。路由组件参数其中的一种其实就是params参数,这个params参数就可以直接写在路径中。

那么我看一下,我们通过参数要把什么传到Details组件中?是不是一个是id另一个是title?可能有人要说,还有一个content啊。我们先别急,我们先把这两个先传过去,只要能传过去还用再在乎content吗?那么怎么传呢?

export default class Message extends Component {
  state = {...}
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {messageArr.map(
            msg => <li key={msg.id}>
              <Link to={`/home/message/detials/{msg.id}/{msg.title}`}>
                {msg.title}
              </Link>
            </li>
          )}
        </ul>
        <Route path="/home/message/detials/:id/:title" component={Details} />
      </div>
    )
  }
}

我们来看一下代码,这是什么意思?其他的是不是都不用管,我们先单看我们的Link标签,这个to属性这么写是什么意思?我是不是要把msg.idmsg.title传给Details组件?这其实就是传递params参数的方法。但是我如果光在<Link>中写的话是不行的,因为注册路由的时候只是会认为你这是模糊匹配,所以说我们再来看注册路由这里,我们要用:id:title来接收我们传入的参数。只有这样Details组件才能收到数据。

那么问一下,现在我们数据也传了,注册路由的时候也接收了,那么接收到的参数存到哪去了?是不是Details组件的props中去了?我们来打印一下看看:

image-20220117123623390

我们先看上面地址路径是不是正常details后面是id在后面就是title,然后来看控制台,在match属性中是不是有一个params属性?这里面就是我们传入进去的参数。那么我们在Details组件中来使用这些参数吧:

const data = [
  { id: 1, content: "Hello world!" },
  { id: 2, content: "Hello React!" },
  { id: 3, content: "Hello jingxun!" },
]

export default class Details extends Component {
  render() {
    const { id, title } = this.props.match.params
    const findResult = data.find(d=>d.id.toString() === id);
    return (
      <ul>
        <li>ID: {id}</li>
        <li>TITLE: {title}</li>
        <li>CONTENT: {findResult.content}</li>
      </ul>
    )
  }
}

我们现在Details组件中定义一个变量来作为我们mock出来的数据,然后解构赋值,从props中取出idtitle,然后再通过iddata中拿到content,然后展示到页面上。我们来看一下效果:

image-20220117125134692

这样我们便成功得将我们想要的效果展示在了页面上。

总结

  • params参数可以直接写咋路由链接路径中
  • 注册路由时要声明接收参数
  • param参数存放在props中的match.params中。

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/pass_params_to_route_component/