React中这几个常用的自定义Hook,你学会了吗?
useSetState
在React
还没有推出hooks
之前,我们写React
组件都是class
组件,在class
中,我们更新状态的方法是setState
,而setState
是会自动帮我们将多个状态进行合并处理的,什么意思呢?
当我们在某个方法中使用setState
修改数据的时候,React
会自动将其它不需要修改的值进行保存,后续我们用到的时候还是之前没有修改过的值,而现在在使用useState
这个hook
时,如果我们设置的状态是一个对象,我们还需要先将没有变化的数据重新赋值回来,这样后面才能用到,类似下面这样的:
// hook 组件
const [state, setState] = useState({
name: 'zhangsan',
age: 18,
});
// 当我们需要修改name,并且不改变age时,我们需要这么写
setState((prev) => {
...prev,
name: 'xxxx'
});
上面的伪代码是在hook
中需要更新多个状态时实现的代码,而class
组件中只需如下这样实现即可:
// class 组件
// 初始化数据
this.state = {
name: 'zhangsan',
age: 18
};
// 修改数据时,我们只需要改变需要修改的值即可
this.setState({
name: 'xxxx'
});
通过对比class
组件和hook
组件,我们发现如果还是class
组件中操作数据的方式更简单一些,那么在hook
中我们该如何实现类似class
组件中的效果呢?
这时候就该useSetState
登场了。useSetState
顾名思义,就是更新组件的状态,官方的介绍如下:
管理 object 类型 state 的 Hooks,用法与 class 组件的 `this.setState` 基本一致。
具体的API
地址在这里,下面我们就一起来用一下这个方法,看看是不是比直接使用useState
要方便。
import { useSetState } from 'ahooks';
interface StateTypes {
name: string;
age: number;
}
const Demo = () => {
const [state, setState] = useSetState<StateTypes>({
name: 'zhangsan',
age: 18
});
return (
<div>
<p>我的名字是{state.name},我今年{state.age}岁</p>
<button onClick={() => setState({ name: 'lisi' })}>点击修改名字</button>
<button onClick={() => setState({ age: 20 })}>点击修改年龄</button>
</div>
)
}
具体的效果可以狠戳这里
这样实现的方式是不是比用useState
要简单很多呢?当然我们光知道怎么使用还不行,我们还需要知道它是如何实现的,下面我们就一起来看一下它的源码吧!
import { useCallback, useState } from 'react';
import { isFunction } from '../utils';
export type SetState<S extends Record<string, any>> = <K extends keyof S>(
state: Pick<S, K> | null | ((prevState: Readonly<S>) => Pick<S, K> | S | null),
) => void;
const useSetState = <S extends Record<string, any>>(
initialState: S | (() => S),
): [S, SetState<S>] => {
const [state, setState] = useState<S>(initialState);
const setMergeState = useCallback((patch) => {
setState((prevState) => {
const newState = isFunction(patch) ? patch(prevState) : patch;
return newState ? { ...prevState, ...newState } : prevState;
})
}, []);
return [state, setMergeState];
};
export default useSetState;
上面的代码中,首先向外部导出了一个SetState
,它的参数是一个泛型S
,而S
的类型其实就是key为string
类型,value为any
类型的对象,意思就是我们可以设定一个对象为它的初始值,而这个对象的key只能字符串,值可以是任意类型。
再来看一下内部的实现,其实也是用的useState
,而我们在外面之所以可以直接修改某个状态,不需要自己手动去获取之前的状态,其实也是内部帮我们实现了一个setMergeState
。在这个代码中,用到setState
,它帮我们将对象中的所有数据都展开,然后帮我们做了数据的合并,这其实就是useSetState
能够这么方便的原理,看到这里,你学会了吗?
useUpdateEffect
除了前面的useSetState
,我们在实际的开发中使用useUpdateEffect
的频次也很高,那么useUpdateEffect
有什么用途呢?官方的介绍是这样的:
`useUpdateEffect` 用法等同于 `useEffect`,但是会忽略首次执行,只在依赖更新时执行。
具体的API
地址在这里,下面我们就一起来用一下这个方法,然后对比一下使用useEffect
的区别。
// ...other code
const [form] = Form.useForm();
const initData = useMemo(() => {
if (!visible) {
return {};
}
return record;
}, [record, visible]);
const handleSubmit = useCallback(() => {
const data = form.getFieldsValue();
onOk(data);
}, [onOk, form]);
useUpdateEffect(() => {
if (visible) {
form.resetFields();
}
}, [visible]);
// ...other code
在上面的代码中,只有当弹窗组件的visible
发生变化时我们才会去清理表单form
中的数据,但是第一次这个组件执行的时候是不会执行useUpdateEffect
里面的方法的,顾名思义只有当状态发生变化(更新)时才会执行相应的代码。
具体的执行效果可以狠戳这里,如下图所示:
当点击修改信息按钮时:
修改完成后页面显示的数据也会更新,具体可以自己点击尝试一下。
下面我们也一起来看一下官网的源码是如何实现的吧,具体的源码地址在这里,具体的代码如下:
// useUpdateEffect
import { useEffect } from 'react';
import { createUpdateEffect } from '../createUpdateEffect';
export default createUpdateEffect(useEffect);
useUpdateEffect
内部的代码只有三行,但是它引入了一个createUpdateEffect
来实现的,那createUpdateEffect
内部是如何实现的呢?我们再一起来看一下吧,代码如下:
// createUpdateEffect
import { useRef } from 'react';
import type { useEffect, useLayoutEffect } from 'react';
type EffectHookType = typeof useEffect | typeof useLayoutEffect;
export const createUpdateEffect: (hook: EffectHookType) => EffectHookType = (hook) => (effect, deps) => {
const isMounted = useRef(false);
hook(() => {
return () => {
isMounted.current = false;
};
}, []);
hook(() => {
if (!isMounted.current) {
isMounted.current = true;
} else {
return effect();
}
}, deps);
}
上面的代码我们主要看的就是内部的isMounted
,通过useRef
保存了一个状态,用于判断是否是初始化加载,这里用useRef
为啥不用useState
呢?在这段代码中,通过判断isMounted
的状态,来决定是否需要去执行副作用effect
,只有当依赖性deps
发生改变时,才会重新去执行,但是第一次加载的时候不会运行,这就是这个函数的基本作用了。
最后
写到这里,关于ahooks
中常用的方法就介绍完毕了,当然ahooks
中还有很多平时很常用的方法,后续会继续分享给大家,如果这篇文章中有什么地方写的不对的地方,欢迎大家在留言区进行讨论。
最后,如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家
往期回顾
转载自:https://juejin.cn/post/7126851071611240461