React Hook/Hooks是什么?
- Hook是React 16.8.0版本增加的新特性/新语法
- 可以让你在函数组件中使用 state 以及其他的 React 特性
三个常用的Hook
- State Hook: React.useState()
- Effect Hook: React.useEffect()
- Ref Hook: React.useRef()
State Hook
-
State Hook让函数组件也可以有
state
状态(虽然函数组件没有this), 并进行状态数据的读写操作 -
语法:
const [xxx, setXxx] = React.useState(initValue)
-
useState()
说明:
参数: 第一次初始化指定的值在内部作缓存
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数 -
setXxx()
2种写法:
setXxx(newValue)
: 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
setXxx(value => newValue)
: 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
demo如下:
import React from 'react'
import ReactDOM from 'react-dom'
function Demo(){
//console.log('Demo');//调用次数:1+n原则,一次初始化+n次状态改变
const [count,setCount] = React.useState(0)
const [name,setName] = React,useState('Tom')
//加的回调
function add(){
//setCount(count+1) //第一种写法
setCount(count => count+1 )//第二种写法
}
//提示输入的回调
function changeName(){
setName('Jack')
}
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={add}>点我+1</button>
<button onClick={changeName}>点我改名</button>
</div>
)
}
export default Demo
效果:
Effect Hook
-
Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
-
React中的副作用操作:
1. 发ajax
请求数据获取
2. 设置订阅 / 启动定时器
3.手动更改真实DOM
-
语法和说明:
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行,
第一个参数是一个函数,这个函数若返回的是函数,则这个返回的函数就相当于componentWillUnmount()
,因此可以在此处进行一些收尾工作。
第二个参数是一个数组,stateValue
相当于监测名单;
- 若为
空数组[]
,则代表什么都不监测,只会在初始化的时候执行一次,相当于componentDidMount()
; - 若省略第二个参数,则说明什么的无论改变都监测,相当于
componentDidUpdate()
。
但是通过useEffect形成的componentDidUpdate
效果与Class式组件中的componentDidUpdate
效果并不是完全一致的。
后者在访问相关属性时,是通过this.props.xxx
进行访问的,其总是指向最新的xxx 值;而前者当 useEffect
没有传入第二个参数,那么第一个参数传入的 effect
函数在每次 render 函数执行是都是独立的。每个 effect
函数中捕获的 props
或 state
都来自于那一次的 render
函数。每一帧可以拥有独立的 Effects
因此,在使用 useEffect 时,应当抛开在 class 组件中关于生命周期的思维。他们并不相同。在 useEffect 中刻意寻找那几个生命周期函数的替代写法,将会陷入僵局,无法充分发挥 useEffect 的能力。
- 可以把 useEffect Hook 看做如下三个函数的组合
componentDidMount()
、componentDidUpdate()
、componentWillUnmount()
demo如下:
import React from 'react'
import ReactDOM from 'react-dom'
function Demo(){
//console.log('Demo');
const [count,setCount] = React.useState(0)
const myRef = React.useRef()
React.useEffect(()=>{
let timer = setInterval(()=>{
setCount(count => count+1 )
},1000)
return ()=>{
clearInterval(timer)
}
},[])
//加的回调
function add(){
//setCount(count+1) //第一种写法
setCount(count => count+1 )
}
//卸载组件的回调
function unmount(){
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={add}>点我+1</button>
<button onClick={unmount}>卸载组件</button>
</div>
)
}
export default Demo
效果:
Ref Hook
- Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
- 语法:
const refContainer = useRef()
- 作用:保存标签对象,功能与
React.createRef()
一样
demo如下:
import React from 'react'
import ReactDOM from 'react-dom'
function Demo(){
const [count,setCount] = React.useState(0)
const myRef = React.useRef()//创建一个ref节点
React.useEffect(()=>{
let timer = setInterval(()=>{
setCount(count => count+1 )
},1000)
return ()=>{
clearInterval(timer)
}
},[])
//加的回调
function add(){
//setCount(count+1) //第一种写法
setCount(count => count+1 )
}
//提示输入的回调
function show(){
alert(myRef.current.value)
}
//卸载组件的回调
function unmount(){
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
return (
<div>
<input type="text" ref={myRef}/>
<h2>当前求和为:{count}</h2>
<button onClick={add}>点我+1</button>
<button onClick={unmount}>卸载组件</button>
<button onClick={show}>点我提示数据</button>
</div>
)
}
export default Demo
效果: