Hookes是React的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。
一、Hooks API
Hooks API分为基础Hook、额外的Hook
基础Hooke
1. useState
usestate的使用
:useState 的使用非常简单,我们从 React 中拿到 useState 后,只需要在使用的地方直接调用 useState 函数就可以, useState 会返回一个数组,第一个值是我们的 state, 第二个值是一个函数,用来修改该 state 的,那么这里为什么叫 count 和 setCount?一定要叫这个吗,这里使用了 es6 的解构赋值,所以你可以给它起任何名字:如updateCount, doCount、any thing,当然,为了编码规范,所以建议统一使用一种命名规范,尤其是第二个值
2. useEffect
Effect Hook
可以让你在函数组件中执行副作用操作,这里提到副作用,什么是副作用呢,就是除了状态相关的逻辑,比如网络请求,监听事件,查找 dom
3. useContext
useContext:
context 中的 Provider
和 Consumer
,在类组件和函数组件中都能使用,contextType
只能在类组件中使用,因为它是类的静态属性
额外的Hooke
1. useReducer
useState
的替代方案。它接收一个形如 (state, action) => newState
的 reducer,并返回当前的 state 以及与其配套的 dispatch
方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)
2. useCallback
useCallback
是什么呢,可以说是 useMemo 的语法糖,能用 useCallback 实现的,都可以使用 useMemo, 在 react 中我们经常面临一个子组件渲染优化的问题, 尤其是在向子组件传递函数props时,每次 render 都会创建新函数,导致子组件不必要的渲染,浪费性能,这个时候,就是 useCallback 的用武之地了,useCallback 可以保证,无论 render 多少次,我们的函数都是同一个函数,减小不断创建的开销。 同样,useCallback
的第二个参数和useMemo
一样,没有区别
3. useMemo
useMemo
是什么呢,它跟 memo 有关系吗 ,说白了 memo 就是函数组件的 PureComponent,用来做性能优化的手段,useMemo 也是,useMemo 在我的印象中和 Vue 的 computed 计算属性类似,都是根据依赖的值计算出结果,当依赖的值未发生改变的时候,不触发状态改变
4. useRef
useRef
有什么作用呢,其实很简单,总共有两种用法
- 获取子组件的实例(只有类组件可用)
- 在函数组件中的一个全局变量,不会因为重复
render
重复申明, 类似于类组件的this.xxx
获取子组件实例
5. useImperativeHandle
useImperativeHandle
可以让你在使用 ref
时自定义暴露给父组件的实例值,说简单点就是,子组件可以选择性的暴露给副组件一些方法,这样可以隐藏一些私有方法和属性
6. useLayoutEffect
其函数签名与 useEffect
相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect
内部的更新计划将被同步刷新。
7. useDebugValue
useDebugValue
接受一个格式化函数作为可选的第二个参数。该函数只有在 Hook 被检查时才会被调用。它接受 debug 值作为参数,并且会返回一个格式化的显示值。
二、useState的手动封装
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/17.0.1/umd/react.development.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/17.0.1/umd/react-dom.development.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
console.log(ReactDOM);
let initState = []
let initIndex = 0
function cutUserState(state) {
let currentIndex = initIndex
initState[currentIndex] = initState[currentIndex] ? initState[currentIndex] : state
function changeState(newState) {
initState[currentIndex] = newState
initIndex=0
render()
}
initIndex++
return [initState[currentIndex], changeState]
}
function App() {
const [count, setCount] = cutUserState(0)
console.log(count);
return (
<div>
<p>{count}</p>
<button onClick={() => {
setCount(count + 1)
}}>+++</button>
</div>
)
}
function render() {
ReactDOM.render(
<App />,
document.getElementById('root')
)
}
render()
</script>
</body>
</html>
复制代码
三、useEffect的手动封装
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/17.0.1/umd/react.development.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/17.0.1/umd/react-dom.development.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function cutUseEffect(callback,deps){
let oldState=initState[initIndex]
let isChange=oldState?[...new Set([...oldState,...deps])].length!==deps.length:false
if(!deps||ischange){
callback()
}
initState[initIndex]=deps
}
function App(){
const [count,setCount]=cutUserState(0)
cutUseEffect(()=>{
console.log('effect count')
},[count])
return (
<div>
<p>{count}</p>
<button onclick={()=>{setCount(count+1)}}>+++</button>
</div>
)
}
function render() {
ReactDOM.render(
<App />,
document.getElementById('root')
)
}
render()
</script>
</body>
</html>
}
复制代码