React Hooks 介绍
-
React Hooks是用来做什么的
- 对函数型组件进行增强,让函数型组件可以存储状态,可以拥有处理副作用的能力。
- 让开发者在不使用类组件的情况下,实现相同的功能。
-
什么是副作用呢?
副作用是函数式编程引入的概念,如果一个函数,相同的输入有相同的输出,那么认为该函数是纯函数。这种情况是没有副作用的,但是如果针对该函数引入不确定的代码,导致输出不确定,那么引入的代码就是该函数的副作用。
在react中,纯函数的概念可以理解为,不管在任何地方渲染,同一个函数,渲染的结果是确认的,所以不是把数据转换成视图的代码,就是副作用代码,比如操作DOM节点,AJAX请求,定时器。
在类组件中,通常使用生命周期来处理这些副作用,而在函数型组件中,使用HOOKS来处理这些副作用。
useState()
-
用于为函数组件引入状态
一个函数当中的变量,在执行完成后,这个变量就会被释放掉,函数型组件本身是不可保存状态数据的,但是在有了useState这个hook以后,函数型组件就可以保留状态,方便下次渲染时使用,useState方法的内部是通过闭包实现保存状态数据的。
-
useState使用上的一些细节
- 接收唯一的参数即状态初始值,初始值可以是任意数据类型。
- 返回值为数组,数组中存储状态值和更改状态值的方法,方法名称约定以set开头,后面加上状态名称。
- 方法可以被调用多次,用来保存不同状态值。
- 参数可以是一个函数,函数返回什么,初始状态就是什么,函数只会被调用一次,用在初始值是动态值的情况。(性能优化)
- 设置状态值方法本身是异步的。
const [count,setCount] = useState(0);
useReducer()
-
useReducer是另外一种让函数组件保存状态的方式
与useState的区别是useReducer更方便于集中管理组件状态,可以将改变值的行为都集中在父组件。
function reducer () {
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
defatule:
return state;
}
}
const [count, dispatch] = useReducer(reducer, 0)
useContext()
- 在跨组件层级获取数据时使用。
import {createContext,useContext} from 'react'
const countContext = createContext();
function App() {
return (
<createContext.Provider value={100}>
<Foo />
</createContext.Provider>
);
}
function Foo() {
const value = useContext(countContext);
return <div>{{value}}</div>
}
export default App;
useEffect()
-
让函数型组件拥有处理副作用的能力,类似生命周期函数。
-
useEffect执行时机。
- useEffect(()=>{}),组件挂载,更新时执行
- useEffect(()=>{}, []) 组件挂载时执行
- useEffect(()=>{ ()=>{} }) 组件卸载前执行
- useEffect(()=>{},[count]) 指定数据发生变化时触发useEffect
-
useEffect 使用方法
- 为window对象添加滚动事件
- 设置定时器让count数值每一秒增加1
-
useEffect 结合异步函数时,不能直接使用async,否则会给hook包裹一层promise
function App() {
useEffect(() => {
(async () => {
let result = await getData()
})()
})
return (
<div></div>
);
}
useMemo()
- useMemo的行为类似Vue中的计算属性,可以监测某个值的变化,根据变化值计算新值。
- useMemo会缓存计算结果,如果检测值没有发生变化,即使组件重新渲染,也不会重新计算,此行为可以有助于避免在每个渲染函数上进行昂贵的计算。
const result = useMemo(() => {
// 如果count值发生变化时此函数重新执行
return result;
}, [count])
Memo()
- 性能优化,如果本组件中的数据没有发生变化,阻止组件更新。
function Foo() {
return <div></div>
}
export default memoo(Counter)
useCallback()
- 性能优化,缓存函数,使组件重新渲染时得到相同的函数实例。
- 如果不加入useCallback,因为传入props的值每次渲染时都会变化,导致Foo组件每次都会重新渲染
import { useState, memo, useCallback } from "react"
function App() {
const [count, setCount] = useState(0);
const resetCount = useCallback(() => setCount(0), [setCount])
return (
<div>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>+1</button>
<Foo resetCount={resetCount} />
</div>
);
}
const Foo = memo(function Foo(props) {
console.log("Foo组件重新渲染了");
return (
<div>
我是Foo组件
<button onClick={props.resetCount}>resetCount</button>
</div>
)
})
export default App;
useRef()
- 获取DOM元素对象。
function App() {
const username = useRef();
const handler = () => console.log(username);//{current: input)
return <input ref={username} onChange={handler} />
}
- 保存数据,即使组件重新渲染,保存的数据仍然还在,保存的数据被更改不会触发组件重新渲染。
function App() {
const [count, setCount] = useState(0);
const timerId = useRef();
useEffect(() => {
timerId.current = setInterval(() => {
setCount(count => count + 1)
}, 1000);
});
const stopCount = function () {
clearInterval(timerId.current)
}
return (
<div>
<button onClick={stopCount}>停止定时器{count}</button>
</div>
)
}