Skip to main content

一些hooks

note

只要页面state发生了变化,那就会触发重新渲染。

useEffect

在页面重新渲染之后执行,异步执行,不会阻塞页面。

note

通常,组件卸载时需要清除effect创建的诸如订阅或计时器ID等资源。要实现这一点,useEffect函数需返回一个清除函数。以下就是一个创建订阅的例子:

useEffect(() => {
const subscription = props.source.subscribe();
return () => {
// 清除订阅
subscription.unsubscribe();
};
});

为防止内存泄漏,清除函数会在组件卸载前执行。另外,如果组件多次渲染(通常如此),则在执行下一个effect之前,上一个effect就已被清除。

useLayoutEffect

在页面重新渲染期间执行。注意这是同步的,所以会阻塞页面加载。

useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

返回一个memoized值。

在页面重新渲染期间执行,返回一个对象。

如果在dom中要增加这个函数,那么直接写明对象本身即可,不需要写成memoizedValue()

useCallBack

const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);

把内联回调函数及依赖项数组作为参数传入useCallback,它将返回该回调函数的memoized版本,该回调函数仅在某个依赖项改变时才会更新。

note
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

在页面重新渲染期间执行。

useImperativeHandle

感觉更多是用来弹出子组件方法。

useImperativeHandle(ref, createHandle, [deps])
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

useRef

note

更多的是用来获取DOM实例。

const refContainer = useRef(initialValue);
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>
</>
);
}

useState

const [state, setState] = useState(initialState);

返回一个state,以及更新state的函数,用来双向绑定数据。

这个set函数是异步的,所以调用之后立马去获取state不一定是新的,如果新的state需要通过使用先前的state计算得出,那么可以将函数传递给setState。该函数将接收先前的state,并返回一个更新后的值。下面的计数器组件示例展示了setState的两种用法。

function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}

useReducer

用处和useState接近,但是在某些场景下,useReducer会比useState更适用,例如state逻辑较复杂且包含多个子值,或者下一个state依赖于之前的state等。并且,使用useReducer还能给那些会触发深更新的组件做性能优化

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>
</>
);
}