React Hook 指南
什么是 Hook?
Hook 是 React 16.8 的新增个性。它能够让你在不编写 class 的状况下应用 state 以及其余的 React 个性。
Hook
实质上就是一个函数,它简洁了组件,有本人的状态治理,生命周期治理,状态共享。
useState
useEffect
useContext
useReducer
Hook 呈现解决了什么?
- [] 组件之间状态复用,例如:应用 useContext 能够很好的解决状态复用问题,或者自定义
Hook
来定制合乎本人业务场景遇到的状态治理。- [] 在函数组件中 生命周期的应用,更好的设计封装组件。在函数组件中是不能间接应用生命周期的,通过
Hook
很好的解决了此问题。- [] 函数组件与 class 组件的差别,还要辨别两种组件的应用场景。应用
Hook
齐全不必去想这些,它能够应用更多React
新个性。
什么时候应用 Hook ?
在函数组件顶层调用
在 函数中应用 / 自定义
Hook
中应用
React
内置的 Hook
useState
状态治理
useEffect
生命周期治理
useContext
共享状态数据
useMemo
缓存值
useRef
获取 Dom 操作
useCallback
缓存函数
useReducer
redux 类似
useImperativeHandle
子组件裸露值 / 办法
useLayoutEffect
实现副作用操作,会阻塞浏览器绘制
useState
状态治理
在
class
组件中,咱们获取state
是 通过this.state
来获取的。而在
函数组件
中, 是没有this
的,咱们能够应用Hook
提供的useState
来治理和保护state
.
useState
定义 / 应用
const [state, setState] = useState(initialState)
setState 为更新 satate 办法
useState(initialState) initialState 为初始值
残缺栗子
import {useState} from 'react';
export default () => {const [data, setData] = useState('微信公众号:前端自学社区')
return (
<div>
<h1>{data}</h1>
{/* 更新 state */}
<button onClick={()=>{setData('微信公众号:前端自学社区 666')}}></button>
</div>
)
}
useEffect
生命周期治理
定义
useEffect
能够看作是函数式 组件
的 生命周期治理。因为在 函数式组件中无奈间接应用生命周期,就必须托管
Hook
来进行治理应用了。
useEffect
能够应用的 3 个生命周期函数:
componentDidmount
componentDidUpdate
componentWillUnmount
无需革除 Effect
应用
什么是无需革除
Effect
应用?React 更新 DOM 之后运行一些额定的代码
那么它就是在生命周期的
compoentDidmount
和componentUpdate
中执行即可。
useEffect(() => {
// 默认会执行
// 这块相当于 class 组件 生命周期的
//compoentDidmount compoentDidUpdate
}, [])
革除Effect
应用
1. 什么是 革除
Effect
?当组件进行卸载时,须要执行某些事件处理时,就须要用到 class 组件生命周期的
componentUnmount
.在
useEffect
中很方便使用,在外部返回一个办法即可,在办法中写相应业务逻辑2. 为什么 要在
Effect
中返回一个函数?这是 effect 可选的革除机制。每个 effect 都能够返回一个革除函数。如此能够将增加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。
useEffect(()=>{return () => {console.log('组件卸载时执行')
}
})
监听 state
变动
能够通过管制 监听
state
变动来实现相应的业务逻辑。
useEffect(() => {
// 监听 num,count 状态变动
// 不监听时为空 [] , 或者不写}, [num, count])
残缺栗子
import {useState, useEffect} from 'react';
export default () => {const [num, setNum] = useState(0)
const [count, setCount] = useState(1)
useEffect(() => {
// 默认会执行
// 这块相当于 class 组件 生命周期的 compoentDidmount compoentDidUpdate
console.log(`num: ${num}`)
console.log(`count: ${count}`)
// 组件在卸载时,将会执行 return 中内容
return () => {
// 相当于 class 组件生命周期的 componentWillUnMount
console.log('测试')
}
}, [num])
return (
<div>
<h1>{num}</h1>
<button onClick={() => { setNum(num + 1) }}> 更新 Num</button>
<hr />
<h1>{count}</h1>
<button onClick={() => { setCount(count + 1) }}> 更新 Count</button>
</div>
)
}
useRef
什么是 useRef
?
useRef
返回的是一个可变的 ref 对象,它的属性 current 被初始化为传入的参数(initialValue),返回的 ref 对象在组件的整个生命周期内放弃不变。作用:
获取 Dom 操作,例如 获取
input
焦点获取子组件的实例(只有类组件可用)
在函数组件中的一个全局变量,不会因为反复 render 反复申明
栗子
import {useRef} from 'react';
export default () => {const inputRef = useRef({value:0})
return (
<div>
<h1> 测试 </h1>
<input type="text" ref={inputRef} />
<button onClick={()=>{console.log(inputRef.current.value)}}> 获取 input 值 </button>
<button onClick={()=>{inputRef.current.focus()}}> 获取 input 焦点 </button>
</div>
)
}
useContext
状态数据共享
Context
解决了什么
在日常开发中,咱们父子组件都是通过
props
来进行通信,如果遇到跨级组件通信
那么咱们就不好通过props
来解决了。这时候能够想想怎么能够把 组件 状态 共享进来应用?
Context
Redux
.....
本大节通过
Context
来 达到组件数据共享
什么是 Context
数据共享,任何组件都可拜访 Context 数据。
在
React
中,组件数据通过prop
来达到 自上而下的传递数据,要想实现全局传递数据,那么能够应用Context
.留神:
Context 次要利用场景在于 很多 不同层级的组件须要拜访同样一些的数据。请审慎应用,因为这会使得组件的复用性变差。
创立 Context
在应用
Context
前提,必须创立它,能够为它独自创立一个文件来治理Context
,
import React from 'react';
export const MyContext = React.createContext();
应用 Context
在应用
Context
时,它通常用在顶级组件(父组件上),它包裹的外部组件都能够享受到state
的应用和批改。通过
Context.Provider
来进行包裹,值通过value = {}
传递。子组件如何应用
Context
传递过去的值 ?
- 通过
useContext()
Hook 能够很不便的拿到对应的值.
// Context.js
import React from 'react';
export const MyContext = React.createContext();
import {useContext} from 'react';
import {MyContext} from '../Context/index'
const result = {
code:200,
title:'增加数据胜利'
}
const Son = () => {const res = useContext(MyContext)
return (
<>
<div>
<h1>{res.code}</h1>
<hr/>
<h2>{res.title}</h2>
</div>
</>
)
}
export default () => {
return (<MyContext.Provider value={result}>
<div>
<h1> 前端自学社区 </h1>
<Son/>
</div>
</MyContext.Provider>
)
}
useMemo
晋升性能优化
定义
useMemo
用于性能优化,通过记忆值来防止在每个渲染上执⾏高开销的计算。
useMemo
参数:
useMemo
返回值是memoized
值,具备缓存作用array
管制useMemo
从新执⾏的数组,array 中 的 state 扭转时
才会 从新执行useMemo
留神:
- 不传数组,每次更新都会从新计算
- 空数组,只会计算一次
- 依赖对应的值,当对应的值发生变化时,才会从新计算(能够依赖另外一个 useMemo 返回的值)
栗子
import {useState, useMemo} from 'react';
export default () => {const [count, setCount] = useState(0)
const [num, setNum] = useState(0)
const newValue = useMemo(()=>{console.log(`count 值为 ${count}`)
console.log(`num 值为 ${num}`)
return count+num
},[count])
return(
<div>
<h1>{count}</h1>
<button onClick={()=>{setCount(count+1)}}>count + 1</button>
<hr/>
<h1>{num}</h1>
<button onClick={()=>{setNum(num+1)}}>Num + 1</button>
<hr/>
<h2>{newValue}</h2>
</div>
)
}
解析栗子
当点击了 5 次更新
num
值,页面中newValue
的值始终显示为 0,这是为什么呢?因为我在
useMemo
监听记录的是count
的值,当count
值发生变化时,页面上的newValue
在会从新计算,尽管你点击了 5 次 更新num
,页面没有更新,然而曾经缓存起来了,当点击 更新count
时,它会 计算count+1 的值 和 num 缓存的值
, 最终后果 为 5。缩小了计算耗费。
useCallback
晋升性能优化
定义
useCallback
能够说是useMemo
的语法糖,能用useCallback
实现的,都能够应用useMemo
, 罕用于 react 的性能优化。
useCallback
的参数:
callback
是一个函数用于解决逻辑array
管制useCallback
从新执⾏的数组,array 扭转时
才会从新执⾏useCallback
应用
它的应用和
useMemo
是一样的,只是useCallback
返回的函数。
import {useState, useCallback} from 'react';
export default () => {const [count, setCount] = useState(0)
const [num, setNum] = useState(0)
const newValue = useCallback(()=>{console.log(`count 值为 ${count}`)
console.log(`num 值为 ${num}`)
return count+num
},[count])
return(
<div>
<h1>{count}</h1>
<button onClick={()=>{setCount(count+1)}}>count + 1</button>
<hr/>
<h1>{num}</h1>
<button onClick={()=>{setNum(num+1)}}>Num + 1</button>
<hr/>
{/* 调用 useCallback 返回的值 */}
<h2>{newValue()}</h2>
</div>
)
}
小结
useMemo
和useCallback
性能相似,都是晋升性能优化。该采纳哪种形式来最佳实际,还有待摸索。
欢送 读者 与 我交换。
<br/>
网上对
useMemo
和useCallback
的认识?
useCallback
如果在函数式组件中的话,的确应该当作最佳实际来用,然而应用它的目标除了要缓存依赖未扭转的回调函数之外(与 useMemo 相似),还有一点是为了可能在依赖产生变更时,可能确保回调函数始终是最新的实例,从而不会引发一些意料之外的问题,我感觉后者才是应用 useCallback 的出发点,而非缓存。因为你想啊,即便不必 useCallback,假如这个回调函数也没有任何依赖状态,我间接把这个函数申明在组件内部不也能够吗?我间接应用 ref 不是更自在吗?<br/><br/>
useMemo
自身名字就是和缓存有关联的,实质上就为了解决一个事件,在 render 外面不要间接创建对象或者办法什么的,因为组件每渲染一次,就会创立一次(比方 style 或者一些常量状态),造成不必要的资源节约。现实状况该当是,如果存在依赖,只在依赖变动时从新创立,不存在依赖,那就只创立一次。外表上看,如果所有状态都用 useMemo,必定没什么问题,但你还需从缓存的代价上来剖析这个问题,如果应用 useMemo 缓存一个状态的代价大于它带来的劣势,那是不是反而事与愿违了?大家对
useMemo
和useCallback
有何认识,欢送在下方评论或者加我探讨。
useImperativeHandle
定义
useImperativeHandle
能够让你在应用ref
时自定义裸露给父组件的实例值。在大多数状况下,该当防止应用ref
这样的命令式代码。useImperativeHandle
该当与forwardRef
一起应用。
useImperativeHandle
作用 :子组件能够裸露给父组件 实例应用
格局: useImperativeHandle(ref,()=>{},[])
- 参数 1:子组件向父组件裸露的实例
- 参数 2:函数,传递的父组件可操作的实例和办法
- 参数 3:监听状态,更新状态
import {useState,useImperativeHandle, forwardRef,useRef} from 'react';
const Son = forwardRef((props,ref) => {const inputRef = useRef(0)
const domRef = useRef()
const [state, setState] = useState('期待')
useImperativeHandle(ref,()=>({focus:() => {inputRef.current.focus()},
domRef
}))
return (
<div>
<h1>{state}</h1>
<hr/>
<input type="text" ref={inputRef}/>
<h2 ref={domRef}> 测试 ---------useImperativeHandle</h2>
</div>
)
})
export default () => {const refFather = useRef(0)
return (
<div>
<h1> 父组件 </h1>
<Son ref={refFather} />
<button onClick={()=>{refFather.current.focus()}}> 获取子组件实例 ------ 获取 input 焦点 </button>
<button onClick={()=>{console.log(refFather.current.domRef.current.innerHTML)}}> 获取子组件实例 ------ 获取 h2 Dom</button>
</div>
)
}
useReducer
定义
它是
useState
的代替计划。它接管一个形如(state, action) => newState
的reducer
,并返回以后的state
以及与其配套的dispatch
办法。如果相熟
Redux
应用的话,用useReducer
就是驾轻就熟了,发车了。
应用 Reducer
实现一个加减器
import {useReducer} from 'react';
export default () => {const [state, dispatch] = useReducer((state,action)=> {switch (action.type){
case 'addNum':
return {num:state.num+1}
case 'subtractNum':
return {num:state.num-1}
}
},{num:0})
return (
<div>
<h2>{state.num}</h2>
<button onClick={()=>{dispatch({type:'addNum'})}}> 减少 num</button>
<button onClick={()=>{dispatch({type:'subtractNum'})}}> 减 num</button>
</div>
)
}
结语
❤️关注 + 点赞 + 珍藏 + 评论 + 转发❤️,原创不易,激励笔者创作更好的文章
如果感觉写得不错,
帮我点个在看 / 赞 / 关注
,公众号:“前端自学社区”
,有你的关注更精彩