一.React的hooks ( 函数组件 )
1. 什么是 Hooks
- React 一直都提倡使用函数组件,但是有时候需要使用 state 或者其他一些功能时,只能使用类组件,因为函数组件没有实例,没有生命周期函数,只有类组件才有.
- Hooks 是 React 16.8 新增的特性,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性.
- 如果在编写函数组件时需要向添加一些 state,以前的做法是必须将其它转化为 class。现在可以直接在现有的函数组件中使用 Hooks.
- 凡是 use 开头的 React API 都是 Hooks.
2.React Hooks 的用法
- userState() 状态钩子
- 纯函数组件没有状态,useState()用于为函数组件引入状态
- useState 唯一的参数就是初始 state
useState 会返回一个数组: 第一项是一个变量,指向状态的当前值, 类似this.state 第二项是一个函数,用来更新状态,类似 setState - 下面的代码看起来更加的轻便简洁,没有了继承,没有了渲染逻辑,没有了生命周期等
示例代码:
import React, {useState} from 'react'
function Parent() {
let [name,setName] = React.useState({
name: '小明',
age:20
})
return (
<div>
<h1>状态的初始值是: {name.name}</h1>
<h1>状态的初始值是: {name.age}</h1>
<button onClick={() => {
setName({
name: '张三',
age:50
})
}}>修改状态的初始值</button>
</div>
)
}
- React 的 useEffect()
- Effect Hook 可以让你在函数组件中执行副作用操作,这里的副作用操作,就是除了状态(数据)相关的逻辑,比如网络请求,监听事件,查找 dom。
useEffect(() => {},[array])
useEffect()接受两个参数,第一个参数是你要进行的异步操作,第二个参数是一个数组,用来给出Effect的依赖项
- 类组件在绑定事件、解绑事件、设定定时器、查找 dom 的时候,是通过 componentDidMount、componentDidUpdate、componentWillUnmount 生命周期来实现的,而 useEffect 会在组件每次 render 之后调用,就相当于这三个生命周期函数,只不过可以通过传参来决定是否调用
决定useEffect的是第二个参数:
- 什么都不传时,组件每次 render 之后 useEffect 都会调用,相当于 componentDidMount 和 componentDidUpdate
- 传入一个空数组 [ ], 只会调用一次,相当于 componentDidMount 和 componentWillUnmount
- 传入一个数组,其中包括变量,只有这些变量变动时,useEffect 才会执行
import React,{useEffect} from 'react';
function Parent() {
let [name,setName] = React.useState({
name: '小明',
age:20
})
useEffect(() => {
console.log('挂载了')
})
useEffect(() => {
return () => {
console.log('卸载了')
}
},[])
useEffect(() => {
console.log('更新了')
},[name])
return (
<div>
<h1>状态的初始值是: {name.name}</h1>
<h1>状态的初始值是: {name.age}</h1>
<button onClick={() => {
setName({
name: '张三',
age:50
})
}}>修改状态的初始值</button>
</div>
)
}
- useRef
useRef跟类中的createRef类似,都可以用来获取DOM对象
import React,{useRef} from 'react';
function Parent() {
let [name,setName] = React.useState({
name: '小明',
age:20
})
let names = useRef()
useEffect(() => {
console.log('挂载了')
console.log(names.current)
})
return (
<div>
<h1 ref={names}>状态的初始值是: {name.name}</h1>
<h1>状态的初始值是: {name.age}</h1>
<button onClick={() => {
setName({
name: '张三',
age:50
})
}}>修改状态的初始值</button>
</div>
)
}
二. React 路由
1.前端路由介绍
现在的前端应用大部分都是 SPA (单页面应用程序),也就是只有一个 HTML 页面的应用程序,因为它的用户体验好,对服务器的压力更小,所以更受欢迎.为了有效的使用单个页面来管理原来多页面的功能,前端路由就出来了.
- 前端路由的功能:让用户从一个视图(页面) 导航到另一个视图(页面),但是一定不会直接发送请求,它只是仅仅改变了浏览器地址栏上的URL
- 前端路由是一套映射规则,在 React 中,是 URL 路径 与 组件 的对应关系
- 使用React路由简单来说,就是配置 路径和组件
目前前端路由主要的模式:
- 基于 URL Hash 的路由
- 基于 HTML5 History API 的路由
2.安装react-router-dom
在项目命令行中,执行 npm install react-router-dom -S 下载到生产环境的依赖中。 在组件中通过对象的解构方式去获取到react-router-dom内置组件,在组件中,按需引入内置组件,在页面中进行使用
3.路由的三个核心组件:Router(BrowserRouter) / Route / Link
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
BrowserRouter as Router:
4.使用 Router 组件包裹整个应用
- Router 组件:包裹整个应用,一个 React 应用只需要使用一次
- 两种常用 Router: HashRouter 和 BrowserRouter
- HashRouter: 使用 URL 的哈希值实现,刷新页面后会导致路由state参数的丢失( localhost:3000/#/first )
- BrowserRouter (推荐) : 使用 H5 的 history API 实现 ,不兼容IE9及以下版本,对路由state参数没有任何影响,因为state保存在history对象中( localhost:3000/first )
import {BrowserRouter as Router} from 'react-router-dom'
const App = () => (
<Router>
<h1>React路由基础</h1>
</Router>
)
ReactDOM.render(<App />,document.getElementById('root'));
5.使用 Link 组件作为导航菜单(路由入口)
Link 组件用来处理 a 链接 类似的功能(Link会在页面中生成一个 a 标签),但设置这里需要注意的,react-router-dom 拦截了实际 a 标签的默认动作,然后根据所有使用的路由模式(Hash 或者 HTML5)来进行处理,改变了 URL,但不会发生请求,同时根据 Route 中的设置把对应的组件显示在指定的位置
Link: 用于指定导航链接 (a标签)
<Link to="/first">页面一</Link>
6.NavLink 组件,NavLink 与 Link 类似,但是它提供了两个特殊属性用来处理页面导航
- NavLink 可以实现路由链接的高亮,通过 activeClassName 指定样式名
- 标签体内容是一个特殊的标签属性
- 通过 this.props.children 可以获取标签体内容
<NavLink activeClassName="active" exact to="/">about</NavLink> |
<NavLink activeClassName="active" exact to="/home">home</NavLink>
activeStyle
当前 URL 与 NavLink 中的 to 匹配的时候,激活 activeStyle 中的样式
activeClassName
与 activeStyle 类似,但是激活的是 className
7.使用 Route 组件配置路由规则和要展示的组件(路由出口)
const First = () => <p>页面一的内容</p>
function App() {
return (
<div>
<Link to="/first">页面一</Link>
Route 组件:指定路由展示组件相关信息
path 属性: 路由规则 (注意: path的属性要和Link组件的to属性一样)
component 属性: 展示组件
Route 组件写在哪里,渲染出来的组件就展示在哪
<Route path="/first" component={First} />
<Route path="/first" render={() => {
return <First />
}} />
</div>
);
}
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('root')
);
8.exact
exact是Route下的一个属性,react路由会匹配到所有能匹配到的路由组件,exact能够使得路由的匹配更严格。 exact的值为bool型,为true时表示严格匹配,为false时为正常匹配。 示例如下:
<Route path="/" component={About} />
<Route path="/home" component={Home} />
<Route path="/" exact component={About} />
<Route path="/home" exact component={Home} />
9.Switch 组件的使用
通常情况下,path 和 component 是一 一 对应的关系 Switch组件 可以提高路由匹配效率 ( 单一匹配 ) ( 只会渲染首个被匹配的组件 )
import {Route,Switch} from "react-router-dom"
<Switch>
<Route path="/" exact component={About} />
<Route path="/home" exact component={Home} />
<Route path="/home" exact component={Test} />
</Switch>
10.Redirect 的使用 ( 重定向 )
- 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到 Redirect 指定的路由
import {Route,Switch,Redirect} from "react-router-dom"
<Switch>
<Route path="/about" exact component={About} />
<Route path="/home" exact component={Home} />
<Redirect to="/home" />
</Switch>
11.编程式导航
- 编程式导航:通过 JS 代码来实现页面跳转
- history 是 React 路由提供的,用于获取浏览器历史记录的相关信息
- push(path): 跳转到某个页面,参数 path 表示要跳转的路径,有历史记录
- replace(path): 跳转到某个页面,没有历史记录
- go(n): 前进或后退到某个页面,参数 n 表示前进或后退页面数量 (比如: -1 表示后退到上一页)
props.history.replace(`/home/message/detail/${id}/${title}`)
props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
props.history.replace(`/home/message/detail`,{id:'',title:''})
function About(props){
return (
<div>
<h1>我是about</h1>
<button onClick={() => props.history.push('/home')}>在about中</button>
history.replace('/home') 它没有历史记录
</div>
)
}
12.向路由组件传递参数
- params 参数
路由链接(携带参数): <Link to='/demo/test/tom/18'>详情</Link>
注册路由(声明接收): <Route path="/demo/test/:name/:age" component={Test} />
接收参数: const {id,name} = this.props.match.params
- search 参数
路由链接(携带参数):<Link to='/demo/test/tom/18'>详情</Link>
注册路由(不需要声明,正常注册就可以): <Route path=" /demo/test" component={Test}/>
接收参数:const {search} = this.props.location
注意: 获取到的search是urlencoded编码字 符串,需要借助querystring解析
import qs from 'querystring';
let obj = {name:'tom',age:18}
console.log(qs.stringify(obj))
let str = 'name=tom&age=18'
console.log(qs.parse(str))
- state 参数
路由链接(携带参数):<Link to={{path:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
注册路由(不需要声明,正常注册就可以): <Route path=" /demo/test" component={Test}/>
接收参数:this.props.location.state
注意点: 刷新页面也可以保留住参数
|