Hooks
Hooks
Hooks 是React 在 v16.7版本后推出的全新特性,用来对函数式组件的内部状态进行维护。
Hooks 使用规则
只在顶层调用Hook
不要在循环,条件或嵌套函数中调用 Hook 。 通过遵循此规则,可以确保每次组件渲染时都以相同的顺序调用 Hook 。
只在 React Functions 调用 Hooks
在Lint中,我们通常会引入eslint-plugin-react-hooks
这个ESlint插件来强制执行这两个规则。
基础 Hooks
State Hook
State Hook
允许您将 React state(状态) 添加到函数式组件中。
useState
每次修改都会生成一个新的state。
State的定义
const _count = useState(0);
const count = _count[0];
const setCount = _count[1];useState
的第一个元素是当前值,第二个元素是允许我们更新第一项元素值的函数。使用
[0]
和[1]
访问它们有点令人困惑,因为它们有特定的含义。如果你熟悉ES6中的数组解构,那么就可以使用下面这种写法。const [count, setCount] = useState(0);
State的修改
<button onClick={() => setCount(count + 1)}>
Click me
</button>State的使用
<p>You clicked {count} times</p>
Ref Hook
useRef
返回一个可变的 ref 对象,其 .current
属性被初始化为传递的参数(initialValue
)。返回的对象将存留在整个组件的生命周期中。
// 定义
const demo = useRef(0);
// 修改
demo.current = 1;
console.log(demo);
// {
// current:1
// }
State Hook vs Ref Hook
State 和 Ref 发生数据变化时的区别:
State Hook | Ref Hook | |
---|---|---|
数据 | 重新生成state | 只改变值 |
画面 | 画面重新渲染 | 不会重新渲染 |
示例:
const [test, setTest] = useState(0);
const test2 = useRef(0);
const log = () => {
setTimeout(() => {
console.log({test});
console.log({test2: test2.current});
}, 3000);
};
{test}/{test2.current}
<Button onClick={() => { setTest(test + 1); test2.current = test2.current + 1; }}>add</Button>
<Button onClick={logs}>logs</Button>
先点击 add 再点击 logs
{ test: 1 }
{ test2: 1 }
先点击 logs 再点击 add
{ test: 0 }
{ test2: 1 }
Effect Hook
Effect Hook
可以视为 componentDidMount
,componentDidUpdate
和 componentWillUnmount
三个生命周期函数的组合。在数据发生变化时执行。
我们可以通过 Effect Hook
对 State 和 props 的变化进行监听。
例子:通过监听list的数据变化,动态变更count。
const [list setlist] = useState({});
const getCount = (list) => { setCount(list.length) };
useEffect(() => {
getCount(list);
}, [list]);
Effect Hook实现生命周期
在函数式组件中,React的原始的生命周期无法使用,我们可以利用Effect Hook的特性模拟生命周期。
组件初始化
componentDidMount()
useEffect(() => {
init();
}, []);组件销毁
componentWillUnmount()
useEffect(() => {
return remove;
}, []);组件更新
componentDidUpdate()
useEffect(() => {
update();
});
Memo Hook
计算属性,类似于Vue 的 computed
通过监听某一个State的变化,返回处理后的State。
用法:
const [test, setTest] = useState(0);
const memoValue = useMemo(() => (test + 1), [test]);
AHook
AHook是阿里巴巴团队封装的自定义Hooks工具集。
State Hooks
useReactive
提供一种数据响应式的操作体验,定义数据状态不需要写useState
, 直接修改属性即可刷新视图。
const state = useReactive({
count: 0,
inputVal: '',
obj: {
value: '',
},
});
<button onClick={()=>state.count+1}>{state.count}</button>
useBoolean
优雅的管理 boolean 值的 Hook。
const [state, { toggle, setTrue, setFalse }] = useBoolean(true);
生命周期
useMount
只在组件 mount 时执行的 hook。
useMount(() => {
message.info('mount');
});
useUnmount
只在组件 unmount 时执行的 hook。
useUnmount(() => {
message.info('unmount');
});
useUpdateEffect
一个只在依赖更新时执行的 useEffect hook。使用上与 useEffect 完全相同,只是它忽略了首次渲染,且只在依赖项更新时运行。
useUpdateEffect(() => {
setUpdateEffectCount((c) => c + 1);
return () => {
// do something
};
}, [count]);
useUpdate
强制组件重新渲染的 hook。
const update = useUpdate();
自定义Hooks
useRouter
一个类似 Vue中 useRouter 的封装。其中push
和replace
方法会返回一个布尔值,True表示跳转前后路径及Query参数不变。
const router = useRouter();
router.go(-1);
router.back();
const isDuplicated = router.push({
path:'./'
query:{
keyword:''
}
});
const isDuplicated = router.replace({
path:'./'
query:{
keyword:''
}
})
useRoute
一个类似 Vue中 useRoute 的封装。
// https://react-admin.dxsuite.cn/#/demo/list/1234?pageNo=1
const route = useRoute();
console.log(route.path); // /demo/list/1234
console.log(route.fullPath); // /demo/list/1234?pageNo=1
console.log(route.params); // { id: '1234' }
console.log(route.query); // { pageNo: '1' }
useTimeFormat
一个时间格式化封装
const timeFormat = useTimeFormat();
console.log(timeFormat.YMD('1619769096036')) // '2021-04-30'
console.log(timeFormat.YMDH('1619769096036')) // '2021-04-30 15'
console.log(timeFormat.YMDHm('1619769096036')) // '2021-04-30 15:51'
console.log(timeFormat.YMDHms('1619769096036')) // '2021-04-30 15:51:12'
console.log(timeFormat.ISO('1619769096036')) // '2021-04-30T07:51:36.036Z'
console.log(timeFormat.ISOStartTime('2021-04-30 15:51:12')) // '2021-04-29T16:00:00.000Z'
console.log(timeFormat.ISOEndTime('2021-04-30 15:51:12')) // '2021-04-30T15:59:59.000Z'
useFormLayout
一个表单栅格参数封装
const formLayout = useFormLayout(); // 'default' | 'large' | 'small'
// {
// labelCol: {span: 4},
// wrapperCol: {span: 6},
// },