React的Hooks跟路由的使用
React hooks
React hooks是什么?
React hooks 是React 16.8中的新增功能。它们使您无需编写类即可使用状态和其他React功能
React Hooks的优势?
- 简化组件逻辑
- 复用状态逻辑
- 无需使用类组件编写
为什么使用 Hooks?
因为函数组件没有生命周期,没有this,没有state
在16.7(beta)当中函数组件一直被当做纯渲染组件使用
常用 hook
在函数组件中,我们没有 this,所以我们不能分配或读取 this.state。我们直接在组件中调用 useState Hook
基本语法:
import {useState} from "react";
let [state,setState] = useState(0);
let [状态的值, 修改状态的方法] = useState(状态的初始值)
在函数组件中,useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合
基本语法:
import {useEffect} from "react";
useEffect(() => {
console.log('更新或者挂载了');
return () => {
console.log('卸载了');
}
}, [监听要更新的数据])
代码案例:
// App根组件
import React, { useState } from "react";
import Child from './Child';
// 函数组件
function App() {
let [data, setName] = useState({
name: '浩克',
age: 28
})
let [show, setShow] = useState(true)
return <div>
{show ? <Child data={data}></Child> : ''}
<button onClick={() => {
setName({ name: '疯狂浩克', age: 10 })
}}>点我</button>
<button onClick={() => {
setShow(false)
}}>卸载</button>
</div>
}
export default App;
// Child子组件
import React, { useState, useEffect } from "react";
function Child(props) {
let { data } = props
let [age, setAge] = useState(8)
useEffect(() => {
console.log('组件更新或者挂载了');
return () => {
console.log('组件卸载了');
}
}, [data.name])
return <div>
<h1>name:{data.name}</h1>
<h1>age:{age}</h1>
<button onClick={() => {
setAge(++age)
}}>+1</button>
</div>
}
export default Child
Hook 使用规则
- 只在最顶层使用 Hook
- 只在 React 函数中调用 Hook
- React 函数组件中
- React Hook 中 - 我自己定义 hook 时,可以调用别的hook
- 所有的 hook 必须 以 use开头
React 路由
路由
当应用变得复杂的时候,就需要分块的进行处理和展示,传统模式下,我们是把整个应用分成了多个页面,然后通过 URL 进行连接。但是这种方式也有一些问题,每次切换页面都需要重新发送所有请求和渲染整个页面,不止性能上会有影响,同时也会导致整个 JavaScript 重新执行,丢失状态。
SPA
Single Page Application : 单页面应用,整个应用只加载一个页面(入口页面),后续在与用户的交互过程中,通过 DOM 操作在这个单页上动态生成结构和内容
优点:
- 有更好的用户体验(减少请求和渲染和页面跳转产生的等待与空白),页面切换快
- 重前端,数据和页面内容由异步请求(AJAX)+ DOM 操作来完成,前端处理更多的业务逻辑
缺点:
- 首次进入处理慢
- 不利于 SEO
前端路由
前端路由只是改变了 URL 或 URL 中的某一部分,但一定不会直接发送请求,可以认为仅仅只是改变了浏览器地址栏上的 URL 而已,JavaScript 通过各种手段处理这种 URL 的变化,然后通过 DOM 操作动态的改变当前页面的结构
- URL 的变化不会直接发送 HTTP 请求
- 业务逻辑由前端 JavaScript 来完成
目前前端路由主要的模式:
- 基于 URL Hash 的路由
- 基于 HTML5 History API 的路由
React Router
React Router 提供了多种不同环境下的路由库
- web
- native
基于 Web 的 React Router
基于 web 的 React Router 为:react-router-dom
npm安装:
npm i -S react-router-dom
组件
BrowserRouter 组件
基于 HTML5 History API 的路由组件
使用
在index.js组件当中引入:
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
HashRouter 组件
基于 URL Hash 的路由组件
使用
在index.js组件当中引入:
import { HashRouter} from 'react-router-dom'
ReactDOM.render(
<HashRouter>
<App />
</HashRouter>,
document.getElementById('root')
);
HashRouter与BrowserRouter的区别
- 从页面的地址栏中可以看出HashRouter是包含
#号的,而BrowerRouter是包含/号的 - BrowerRouter的开启需要后端配置的,类似于Vue中的history模式。HashRouter类型于Vue中的hash模式
Route 组件
通过该组件来设置应用单个路由信息,Route 组件所在的区域就是就是当 URL 与当前 Route 设置的 path 属性匹配的时候,后面 component 将要显示的区域
exact
exact 属性表示路由使用 精确匹配模式,非 exact 模式下 ‘/’ 匹配所有以 ‘/’ 开头的路由
import React, { useState } from 'react';
import { Route } from 'react-router-dom';
import IndexPage from './view';
import AboutPage from './view/about';
import HomePage from './view/home';
import Nav from './component/nav';
function App() {
const [state, setstate] = useState('initialState')
return (
<div>
{/* link组件 只改变URL */}
<Nav></Nav>
{/* path属性 匹配URL */}
<Route path="/" exact component={IndexPage} />
<Route path="/about" exact component={AboutPage} />
<Route path="/about/home" exact component={HomePage} />
</div>
);
}
export default App;
Link 组件
Link 组件用来处理 a 链接 类似的功能(它会在页面中生成一个 a 标签),但设置这里需要注意的,react-router-dom 拦截了实际 a 标签的默认动作,然后根据所有使用的路由模式(Hash 或者 HTML5)来进行处理,改变了 URL,但不会发生请求,同时根据 Route 中的设置把对应的组件显示在指定的位置
to 属性
to 属性类似 a 标签中的 href
NavLink 组件
NavLink 与 Link 类似,但是它提供了两个特殊属性用来处理页面导航
activeStyle
当当前 URL 与 NavLink 中的 to 匹配的时候,激活 activeStyle 中的样式
activeClassName
与 activeStyle 类似,但是激活的是 className
import React from "react";
import { NavLink } from "react-router-dom";
export default function Nav() {
return (<nav>
<NavLink to="/" exact activeClassName="active" activeStyle={{ color: 'cyan' }}>首页</NavLink>
<span> | </span>
<NavLink to="/about" exact activeClassName="active-about" activeStyle={{ color: 'orange' }}>关于</NavLink>
<span> | </span>
<NavLink to="/about/home" exact activeClassName="active-home" activeStyle={{ color: 'pink' }}>我的</NavLink>
<span> | </span>
</nav>)
}

从上面的图片中可以看到,点击那个,对应的那个路由的样式以及class名会显示出来,剩下的另外两个不显示。
注意:exact属性必不可少,如果不写这个属性的话,它的所有样式都会出来
传递 props
<Route exact path='/' component={Home}>
如果 Route 使用的是 component 来指定组件,那么不能使用 props
Route : render
<Route exact path='/' render={() => <Home items={this.state.items} />} />
通过 render 属性来指定渲染函数,render 属性值是一个函数,当路由匹配的时候指定该函数进行渲染
动态路由
为了能给处理上面的动态路由地址的访问,我们需要为 Route 组件配置特殊的 path
动态路由铺垫
就是为了给不同的组件传递不同的参数
路由参数
- history : 历史记录以及路由给我们的一些操作
- location : 获取当前URL的一些信息
- pathname : 当前的URL
- search : 接口参数
- state : 跳转路由时,传递的参数
- match : 当前路由匹配的相关规则
- params : 动态路由传过来的参数
hooks (Router5.0之后出现的)
- 不在类组件内使用
- useHistory : 获取History对象
- useLocation : 获取Location对象
- useParams : 获取Params
- useRouteMatch : 获取Match
Switch 组件
该组件只会渲染首个被匹配的组件
- index组件
import React from "react";
import { Link, useParams } from "react-router-dom";
export default function IndexPage(props) {
console.log(useParams());
return (
<div>
<h1>留言列表</h1>
<Link to="/list/1" >1</Link>
<span> | </span>
<Link to="/list/2" >2</Link>
<span> | </span>
<Link to="/list/3" >3</Link>
<span> | </span>
<Link to="/list/4" >4</Link>
<span> | </span>
<Link to="/list/5" >5</Link>
<span> | </span>
<Link to="/list/6" >6</Link>
</div>
)
}
- App组件
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import IndexPage from './view';
function App() {
return (
<div>
<Switch>
<Route path="/list/:page" exact render={(props) => {
return <IndexPage {...props} />
}}></Route>
</Switch>
</div>
);
}
export default App;

withRouter 组件(高阶组件,高阶函数,高阶路由)
如果一个组件不是路由绑定组件,那么该组件的 props 中是没有路由相关对象的,虽然我们可以通过传参的方式传入,但是如果结构复杂,这样做会特别的繁琐。幸好,我们可以通过 withRouter 方法来注入路由对象
// AboutPage
import React from "react";
import HomePage from "./home";
export default function AboutPage() {
return (
<div>
<h1>关于</h1>
<HomePage use={"爱蜜莉雅"}></HomePage>
</div>
)
}
// HomePage
import React from "react";
import { withRouter } from "react-router-dom";
function HomePage(props) {
console.log(props);
return <h1>我的</h1>
}
export default withRouter(HomePage)
// App
import React from 'react';
import { Route } from 'react-router-dom';
import AboutPage from './view/about';
function App() {
return (
<div>
<Route path="/about" exact component={AboutPage}></Route>
</div>
);
}
export default App;