useReducer
const [state, dispatch] = userReducer(reducer, initialArg, init)
useState的替代方案。
在某些场景下,useReducer会比useState更适用:
1.state逻辑较复杂且包含多个子值;
2.下一个state依赖于之前的 state;
3.useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数 。
// 没看懂
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
)
}
如果你想要类似class中的this功能,可以使用一个ref来保存一个可变的变量。
function Example(props) {
// 把最新的props保存在一个ref中
const lastestProps = useRef(props)
useEffect(() => {
lastestProps.current = props
});
useEffect(() => {
function tick() {
// 在任何时候读取最新的props
console.log(lastestProps.current)
}
const id = setInterval(tick, 1000)
return () => clearInterval(id)
}, []); // 这个effect从不会重新执行
}
我该如何实现 shouldComponentUpdate?
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b)
},
[a, b]
)
返回一个memoized回调函数。 把内联回调函数及依赖项数组作为参数传入useCallback,它将返回该回调函数的memoized版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要(例如shouldCompopnentUpdate)的子组件时,它将非常有用(?) useCallback(fn, deps)相当于useMemo(() => fn, deps)
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
返回一个memoized值。 把“创建”函数和依赖项数组作为参数传入useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。 如果没有提供依赖项数组,useMemo在每次渲染时都会计算新的值。
useRef
const refContainer = useRef(initialValue);
useRef返回一个可变的ref对象,其.current属性被初始化为传入的参数(initialValue)。返回的ref对象在组件的整个生命周期内持续存在。
function TextInputWithFocusButton() {
const inputEl = useRef(null)
const onButtonClick = () => {
// `current` 指向已挂载到DOM上的文本输入元素
inputEl.current.focus();
}
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
)
}
useImperativeHandle
useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle可以让你在使用ref时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。 useImperativeHandle应当与forwardRef一起使用:
function FancyInput(props, ref) {
const inputRef = useRef()
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus()
}
}))
return <input ref={inputRef} ... />
}
FancyInput = forwardRef(FancyInput)
在本例中,渲染的父组件可以调用inputRef.current.focus()