上一篇介绍了基础的 Hooks,这一篇接着上一篇介绍下额外的 Hooks.
React Hooks
1. useRef 获取 DOM 的节点或节点内容
const refContainer = useRef(initialValue);
用法:
- 使用用 ref 引用一个值
- 通过 ref 操作 DOM
- 避免重复创建 ref 的内容
useRef
返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue
)。返回的 ref 对象在组件的整个生命周期内保持不变。
import React, { createRef, useRef } from 'react'
export default function UseRef() {
const inputRef = useRef<any>()
const getFocus = () => {
inputRef.current.focus()
console.log(inputRef.current)
console.log(inputRef.current.value)
}
return (
<>
<input type="text" ref={inputRef} />
<button onClick={getFocus}>获取焦点</button>
</>
)
}
问题:无法获取自定义组件的ref
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;
默认情况下,自定义组件不会暴露它们内部 DOM 节点的 ref。
想要 暴露其 DOM 节点的组件必须选择该行为。一个组件可以指定将它的 ref “转发”给一个子组件。
解决:将自定义组件包裹在forwardRef
中然后再使用
const MyInput = forwardRef((props, ref) => {
return <input {...props} ref={ref} />;
});
import { forwardRef } from 'react';
const MyInput = forwardRef(({ value, onChange }, ref) => {
return (
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
});
export default MyInput;
最后,父级组件就可以得到它的 ref。
2. useCallback 缓存一个函数,当依赖项发生改变的时候触发回调函数
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
)
import React, { useState, useCallback } from 'react'
export default function UseCallback():any {
const [count, setCount] = useState<number>(1)
const addNum = () => {
setCount(() => count + 1)
}
const addCallback = useCallback((): void => {
console.log('count改变了:', count)
},[count])
return (
<>
<h2>count的值为:{ count }</h2>
<button onClick={addNum}>Btn1</button>
{/* <button onClick={addCallback}>Btn2</button> */}
</>
)
}
3. useMemo 用来缓存一个值或者计算结果,可以用来做性能优化
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
import React from 'react'
import {useState, useMemo} from 'react'
import UseEffect from './UseEffect'
export default function UseMemo () {
// useMemo的作用是缓存一个值或者计算结果,当值或结果发生改变的时候,重新计算。
// 可以理解为vue中的computed就算属性
const [count, setCount] = useState<number>(1)
const [count2, setCount2] = useState<number>(1)
// const result = () => count * count
// 缓存这个计算结果,当依赖项count2发生改变的时候 result的结果重新计算
// 注意:依赖项[count2]是包含在数组中的,意思是可以有多个依赖项
const result: number = useMemo(():any => count * count, [count2])
return (
<div>
<h1>我是useMemo组件</h1>
<h2>count: {count}</h2>
<h2>count2: {count2}</h2>
<h1>result的结果:{result}</h1>
<button onClick={() => setCount(count + 1)}>count +</button>
<button onClick={() => setCount2(count2 + 1)}>count2 +</button>
</div>
)
}
4. useReducer
useReducer
来操作更多的自变量,相当于多个useState
useState
的替代方案- 它接收一个形如
(state, action) => newState
的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法
const [state, dispatch] = useReducer(reducer, initialArg, init);
import React, {useState, useReducer} from 'react'
export default function UseReducer() {
/**
* 在使用useReducer的时候,需要传递2个参数
第一个是reducer的function, 第二个是初始化数据
它和redux中的数据流很相似,如果要改变数据只能通过dispatch派发一个action
const [state, dispatch] = useReducer(reducer, initialState)
它接受reducer函数和状态的初始值作为参数,返回一个数组,其中第一项为当前的状态值,第二项为发送action的dispatch函数
*/
// 申明一个 reducer 方法
const reducer = (state: any, action: any): any =>{
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 }
case 'decrement':
return { ...state, count: state.count - 1 }
default:
return state
}
}
const [state, dispatch] = useReducer(reducer, {
count: 1,
name: 'Reducer Demo',
list: ['Apple', 'Banana', 'Mango']
})
return (
<>
<h2>UseReducer</h2>
<button onClick={()=> dispatch({type: 'increment'})}>+{ state.count }</button>
<button onClick={()=> dispatch({type: 'decrement'})}>-{ state.count }</button>
</>
)
}