本文涉及到 useState useReducer useContext useEffect useRef useMemo useCallback
这几个常用的hook,会简单讲讲各个hook的作用与使用场景。
useState & useReducer
const [state, setState] = useState(initialState)
useState用于管理页面中的状态,返回当前状态和改变当前状态的方法,可以说是最常用的hook。
const [state, dispatch] = useReducer(reducer, initialState)
useReducer用于保存页面中复杂结构的状态,返回当前状态和改变当前状态的方法。
至于为什么要将这两个hook放在一起说明,是因为这两个hook的实现逻辑是一样的,从源码角度来说,useState只是预设了reducer的useReducer。
能用useReducer实现的功能,同样可以用useState实现,只不过当状态结构比较复杂时,用useReducer实现会更为方便。
下面分别用useState和useReducer实现了一个累加器:
function CounterByUS() {
const [num, setNum] = useState(0)
return (
<>
{sum}
);
}
function CounterByUR() {
const [sum, dispatch] = useReducer((state, action) => {
return state + action;
}, 0);
return (
<>
{sum}
);
}
可见 useState 实现的功能,同样可用 useReducer实现。
useContext
如果页面层级较深,并且需要子组件触发state变化,可以考虑 useReducer+useContext
实现,思路就是把useReducer返回的dispatch函数作为Context中的value共享到Context包裹的所有子组件。
useContext是以Hook的方式使用React.Context,对它所包含的组件树提供全局共享数据,使用方式如下:
const ThemeContext = React.createContext();
function Header(props){ const {color} = useContext(ThemeContext); return header}
useEffect
useEffect(callback,deps)
当deps中的内容变化,执行callback。
一般用于剥离副作用,比如网络请求。
useMemo & useCallback
callback() = useMemo(callback,deps)
当deps中的内容变化,执行callback并返回结果。
可以缓存结果,一般用于性能优化。
callback = useCallback(callback,deps)
当deps中的内容变化,返回callback函数。
可以缓存函数,一般用于性能优化。
useMemo与useCallback的使用场景类似,通过它们对结果或者函数进行缓存达到性能优化的目的,减少不必要的执行。
useRef
{current: initialValue} = useRef(initialValue)
返回一个简单对象{current: initialValue}, 与自建的对象的区别在于,ref对象在整个生命周期内保持不变。
可以通过ref属性绑定到组件上获得组件的引用,也可以通过ref赋予父组件调用子组件方法的能力。
可以绑定到input上以控制焦点,也可以绑定到子组件上调用子类方法,演示代码如下:
function RefDemo() {
const domRef = useRef(1);
const childRef = useRef(null);
const showChild = () => {
childRef.current.say();
};
return (
这是外层组件
{
domRef.current.focus();
domRef.current.value = 'hello';
}}
>
这是子组件
);
};
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
say: sayHello,
}));
const sayHello = () => {
alert("hello,我是子组件");
};
return 子组件
;
});
forwardRef
会创建一个React组件,这个组件能够将其接受的ref属性转发到其组件树下的另一个组件中。useImperativeHandle(ref,createHandle,[deps])
可以将自定义函数暴露给父组件的实例值。useImperativeHandle
应该与forwradRef
搭配使用