React 笔记 2 - 组件通信,路由

204 阅读4分钟

跳过

56-64 todo_list案例
67-70 github搜索案例
71 引入pubsub(订阅发布)用于任意组件间通信
94-96 antd

问题

onclick, bind, 箭头函数
oclick, 传递参数

参考

尚硅谷React技术全家桶全套完整版

脚手架配置代理

方法一

在package.json中追加如下配置

"proxy": "http://localhost:5000"

说明:

  1. 优点:配置简单,前端请求资源时可以不加任何前缀。
  2. 缺点:不能配置多个代理。
  3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)

方法二

  1. 第一步:创建代理配置文件
src下创建配置文件:src/setupProxy.js
  1. 编写setupProxy.js配置具体代理规则:
const proxy = require('http-proxy-middleware')

module.exports = function(app) {
 app.use(
   proxy('/api1', {  //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
     target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
     changeOrigin: true, //控制服务器接收到的请求头中host字段的值
     /*
            changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
            changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
            changeOrigin默认值为false,但我们一般将changeOrigin值设为true
     */
     pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
   }),
   proxy('/api2', { 
     target: 'http://localhost:5001',
     changeOrigin: true,
     pathRewrite: {'^/api2': ''}
   })
 )
}

说明:

  1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
  2. 缺点:配置繁琐,前端请求资源时必须加前缀。

fetch 发送请求

fetch(`/api1/search/users2?q=${keyWord}`)
.then(
  response => {
    console.log('联系服务器成功了');
    return response.json()
  },
  error => {
    console.log('联系服务器失败了',error);
    return new Promise(()=>{})  // 用于中断 promise 链
  }
)
.then(
  response => {console.log('获取数据成功了',response);},
  error => {console.log('获取数据失败了',error);}
)
try {
  const response= await fetch(`/api1/search/users2?q=${keyWord}`)
  const data = await response.json()
  console.log(data);
  PubSub.publish('atguigu',{isLoading:false,users:data.items})
} 
catch (error) {
  console.log('请求出错',error);
  PubSub.publish('atguigu',{isLoading:false,err:error.message})
}

组件通信

父=>子:props。
子=>父:通过 props 父给子传递一个函数。
任意组件:pubsub.js

路由原理

Html5推出的history可以监听到路径变化,还可以直接修改路径同时让页面不跳转。

<a href="http://www.atguigu.com" onclick="return push('/test1') ">push test1</a>

<script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
let history = History.createBrowserHistory()
function push (path) {
  history.push(path)
  return false
}
history.listen((location) => {
  console.log('请求路由路径变化了', location)
})

路由的基本使用

1.明确好界面中的导航区、展示区
2.导航区的a标签改为Link标签
<Link to="/xxxxx">Demo</Link>
3.展示区写Route标签进行路径的匹配
<Route path='/xxxx' component={Demo}/>
4.<Link><Route> 外侧需要包裹 <BrowserRouter><HashRouter>,也可以包裹在 <App> 的外侧。

路由组件与一般组件

路由组件指写在 <Route> 中的组件。
一般组件:<Demo/>
路由组件:<Route path="/demo" component={Demo}/>

路由组件的 props 会接收到三个固定的属性:history, location, match。

通常把路由组件放在 pages 文件夹中,一般组件放入 components 文件夹中。

NavLink的使用

自带一个属性 activeClassName,用于指定选中时的样式。

封装NavLink

对任意标签,标签体内容等价于标签属性 children。可以通过 this.props.children 获取标签体内容。

<NavLink to="/about">About</NavLink>
// 等价于
<NavLink to="/about" children="About" />

Switch的使用

Switch可以提高路由匹配效率(单一匹配)。

解决多级路径刷新页面样式丢失的问题

因为 HTML 中引入 css 使用了相对路径导致的。

<link rel="stylesheet" href="./css/bootstrap.css">

多级路径导致 . 表示的相对路径发生了变化,所以没能获取到正确的样式。

<MyNavLink to="/atguigu/about">About</MyNavLink>

严格匹配与模糊匹配

默认是模糊匹配,即 to="/home/a/b" 可以匹配 path="/home",使用 exact 开启严格匹配。

<Route exact={true} path="/about" component={About} />

Redirect的使用

一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。
<Redirect to="/about"/>

嵌套路由

路由的匹配是按照注册路由的顺序进行的。

向路由组件传递参数

  1. params参数
    路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情</Link>
    注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>
    接收参数:this.props.match.params

  2. search参数
    路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>
    注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
    接收参数:this.props.location.search
    备注:获取到的 search 是 urlencoded 编码字符串,需要借助 querystring 解析

import qs from 'querystring';
const { search } = this.props.location;
const { id, title } = qs.parse(search.slice(1));
  1. state参数
    路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
    注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
    接收参数:this.props.location.state
    备注:刷新也可以保留住参数。state 实际存放在 history 身上。

push 与 replace 模式

<MyNavLink replace to="/home/news">News</MyNavLink>

编程式路由导航

借助this.props.history对象上的API对操作路由跳转、前进、后退
this.props.history.push()
this.props.history.replace()
this.props.history.goBack()
this.props.history.goForward()
this.props.history.go()

withRouter的使用

withRouter可以加工一般组件(例如非页面的组件),让一般组件具备路由组件所特有的API,如 this.props.history 等。
(对于 vue 则不存在此问题,因为 vue 中一般组件也带了这些API)

BrowserRouter 与 HashRouter 的区别

和 vue 相同的地方不再赘述。=> 路由器的两种工作模式
因为state保存在history对象中,所以 HashRouter 刷新后会导致路由 state 参数的丢失。