上节课我们学习了如何向路由组件传递search参数,这节课我们来学习如何向路由组件传递参数的最后一种方式,state参数的传递。

回顾

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

  • search参数不需要声明接收
  • search参数存放在propslocation.search属性中
  • search参数传参方法和query参数一模一样

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

概述

在前两节课的学习中我们学习了两种向路由组件传递参数的方法了,这节课是最后一种方法,但是我们在开始学习之前,我们要着重地说一下,state参数和组件的state是两码事,这个state参数是路由的一个特殊参数,跟组件的那个state没有任何关系,大家千万不要搞混了。

通过前两节课的学习呢,前面两种传参方法大家可能都能看出来,这两个东西在url中都有体现出来,不管之前那两种方法中的哪一种,我们都可以在url上面看见我们传递的参数。但是state参数就不会在url中体现出来,我们在url中看不到我们传递的任何state参数。

用法

我们现在知道了关于state参数的两个特点

  • state参数与组件的state没有任何关系
  • state参数不会出现在url

那么我们应该如何给路由组件传递state参数呢?首先我们在设置路由链接时就要改变我们的写法,我们要求设置路由链接时如果要传递state参数的话,就要把to属性写成一个对象,而不再像之前那样写成字符串就可以了。这个对象也要有两个属性:

  • pathname这个就是我们的路径
  • state,这个state也要是个对象,然后里面就是我们要传的参数

那么我们在设置路由链接的时候有严格要求,要将to属性写成一个对象,那么在接收参数的时候有什么要求吗?比如像params参数要声明接收一样。其实state参数和search参数一样,不需要声明接收,直接保持正常注册即可。

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

我们来看一下代码,to属性要改写成对象,那么是不是要用双花括号?然设置路径名属性和state属性。那么传参没问题了,我们在Details组件中应该怎么取参数呢?

按照我们的正常流程,把数据传到组件中,那肯定是存放在props中了,只不过我们这个是路由组件,props里面的结构比较复杂,我们要去找数据存在props的哪个属性中了,那么我们来看一下这次我们的参数又存放在哪里了:

image-20220117141545708

我们知道,match属性是只存params参数的,理论上应该不会存放state参数,那么验证一下吧,果然没有。再来看locationsearch是空的,因为我们并没有传search参数,但是紧挨着search的下面我们发现了有一个state属性,里面正是我们传的参数。

那就简单了,这次不像search参数那样还要解析,这就是一个对象,直接拿来解构赋值就好了。

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.location.state;
    const findResult = data.find(d=>d.id === id);
    return (
      <ul>
        <li>ID: {id}</li>
        <li>TITLE: {title}</li>
        <li>CONTENT: {findResult.content}</li>
      </ul>
    )
  }
}

那么我们来看代码,正常的直接诶拿location.state来解构赋值,后面的都是一样的操作,我就不再赘述了。那么我们来看一下效果吧:

image-20220117142721012

页面正常扎实呢,数据也正常,但是浏览器的地址栏里面看不见我们传的参数。那么我来问大家一个问题,我们地址栏里面没有参数,那么我们刷新一下,会怎么样呢?

image-20220117143038546

刷新了一下之后我们看到这个state变成了undefined。这倒也很容易理解,因为我们地址栏里什么都没有,如果刷新了之后光从路径上面来看根本不知道这个到底是点了那条message,那么也不知道参数是什么,那么肯定就丢了嘛。

但是大家会过头来看地址栏中的url。里面是不是有个#?我们一直在用HashRouter,那么我们改成BrowserRouter的话,不论我们怎么刷新,都还会正常显示:

image-20220117143542920

为什么呢?因为BrowserRouter会一直操作浏览器的历史记录,所以说我们每一次操作BrowserRouter其实都是知道的。所以说即便当我们刷新了,BrowserRouter都可以通过history来知道我们的参数到底是什么。

以上便是传递state参数的相关内容。

总结

  • state参数在设置路由链接时to属性要写成一个对象
  • pathname为路由链接的路径
  • state为我们要传的参数,是一个对象
  • state参数在props.location.state
  • 当使用BrowserRouter时,刷新也依然可以保留住参数,但是HashRouter不行

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_state_to_route_component/