介绍

主要包含:useCreation(结合 useMemo 或 useRef)、useEventEmitter(共享事件通知、useReactive(另一种useState)

在线地址 Domesy/Advanced

结合 useMemon 或 useRef

  • useCreation:是 useMemo 或 useRef 的替代品。
  • useMemo 不能保证被 memo 的值一定不会被重计算,而 useCreation 可以保证这一点
  • useRef 在基础上与 useCreation 使用场景类似,但在复杂常量的创建,useRef 却容易出现潜在的性能隐患
  • 如何使用:function useCreation(factory: () => T, deps: any[]): T
  • factory: 用来创建所需对象的函数,deps:触发的依赖项

代码演示

image.png

详细地址

  1. import React, { useState } from 'react';
  2. import { Button } from 'antd';
  3. import { useCreation } from 'ahooks';
  4. class Foo {
  5. constructor() {
  6. this.data = Math.random();
  7. }
  8. data: number;
  9. }
  10. const Mock: React.FC<any> = () => {
  11. const foo1 = new Foo();
  12. const foo = useCreation(() => new Foo(), []);
  13. const [, setFlag] = useState({});
  14. return (
  15. <>
  16. <div>未加入useCreation:{foo1.data}</div>
  17. <div style={{marginTop: 8}}>组件渲染,却不会影响Foo的实例:{foo.data}</div>
  18. <Button type='primary' style={{marginTop: 8}} onClick={() => {
  19. setFlag({});
  20. }}>渲染</Button>
  21. </>
  22. );
  23. };
  24. export default Mock;

共享事件通知

  • useEventEmitter:适合的是在距离较远的组件之间进行事件通知,或是在多个组件之间共享事件通知。
  • 当页面十分复杂的时候,我们需要事件的共享(而非参数的共享),这时我们需要 useEventEmitter
  • useEventEmitter 相当于 useImperativeHandle 的增强版,他可以多层级的传递,多个组件进行共享事件通知
  • 如何使用: const click = useEventEmitter();
  • 绑定事件(订阅事件): click.useSubscription(callback: (val: T) => void)=> void
  • 调取事件(发送通知): click.emit(val: T) => void

代码演示

image.png

详细地址

  1. import React, { useState, useRef } from 'react';
  2. import { Button } from 'antd';
  3. import { useEventEmitter } from 'ahooks';
  4. import { EventEmitter } from 'ahooks/lib/useEventEmitter';
  5. const Children: React.FC<{click: EventEmitter<number>}> = ({ click }) => {
  6. const [ count, setCount ] = useState<number>(0);
  7. const ref = useRef<any>(null)
  8. click.useSubscription((val) => {
  9. val === 1 ? message.info('父组件点击的') : message.info('兄弟节点点击的')
  10. ref.current.click();
  11. })
  12. const onClick = () => {
  13. setCount(v => v+1)
  14. }
  15. return <>
  16. <div>点击次数:{count}</div>
  17. <Button ref={ref} type='primary' style={{margin: '8px 0'}} onClick={onClick} >子组件点击</Button>
  18. </>
  19. }
  20. const Children1: React.FC<{click: EventEmitter<number>}> = ({click}) => {
  21. return <Button style={{marginTop: 8}} type="primary" onClick={() => click.emit(2)}>兄弟节点点击</Button>
  22. }
  23. const Mock: React.FC<any> = () => {
  24. const click = useEventEmitter<number>();
  25. return (
  26. <>
  27. <Children click={click} />
  28. <div>
  29. <Button type='primary' onClick={() => {
  30. click.emit(1)
  31. }} >父组件组件点击</Button>
  32. </div>
  33. <Children1 click={click} ></Children1>
  34. </>
  35. );
  36. };
  37. export default Mock;

竞态锁

  • useLockFn:用于给一个异步函数增加竞态锁,防止并发执行。

代码演示

image.png

详细地址

  1. import React, { useState } from 'react';
  2. import { Button } from 'antd';
  3. import { useLockFn } from 'ahooks';
  4. function mockApiRequest() {
  5. return new Promise((resolve:any) => {
  6. setTimeout(() => {
  7. resolve();
  8. }, 2000);
  9. });
  10. }
  11. const Mock: React.FC<any> = () => {
  12. const [count, setCount] = useState(0);
  13. const submit = useLockFn(async () => {
  14. message.info('开始执行')
  15. await mockApiRequest();
  16. setCount((v) => v + 1)
  17. message.info('执行结束')
  18. })
  19. return (
  20. <>
  21. <div>点击次数:{count}</div>
  22. <Button style={{marginTop: 8}} type='primary' onClick={submit} >点击</Button>
  23. </>
  24. );
  25. };
  26. export default Mock;

另一种useState

  • useReactive:一种数据响应式的操作体验,定义数据状态不需要写useState , 直接修改属性即可刷新视图。
  • 可进行任意属性的复制,包括操作属性,类似于全局变量,可以直接改变

代码演示

image.png

详细地址

  1. import React, { useState } from 'react';
  2. import { Button } from 'antd';
  3. import { useReactive } from 'ahooks';
  4. const Mock: React.FC<any> = () => {
  5. const state = useReactive<any>({
  6. count: 0,
  7. inputVal: 'hello',
  8. bool: false,
  9. arr: [],
  10. bug: '',
  11. bugs: ['domesy', 'react', 'hook'],
  12. addBug(bug:string) {
  13. this.bugs.push(bug);
  14. },
  15. get bugsCount() {
  16. return this.bugs.length;
  17. },
  18. });
  19. return (
  20. <>
  21. <div style={{fontWeight: 'bold'}}>基本使用:</div>
  22. <div style={{marginTop: 8}}> 对数字进行操作:{state.count}</div>
  23. <div style={{margin: '8px 0', display: 'flex',justifyContent: 'flex-start'}}>
  24. <Button type="primary" onClick={() => state.count++ } >加1</Button>
  25. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.count-- } >减1</Button>
  26. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.count = 5 } >设置为5</Button>
  27. </div>
  28. <div style={{marginTop: 8}}> Boolean进行操作:{state.bool ? 'true' : 'false'}</div>
  29. <div style={{margin: '8px 0', display: 'flex',justifyContent: 'flex-start'}}>
  30. <Button type="primary" onClick={() => state.bool = !state.bool } >切换状态</Button>
  31. </div>
  32. <div style={{marginTop: 8}}> 对字符串进行操作:{state.inputVal}</div>
  33. <div style={{margin: '8px 0', display: 'flex',justifyContent: 'flex-start'}}>
  34. <Button type="primary" onClick={() => state.inputVal = 'hello' } >设置为 hello</Button>
  35. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.inputVal = 'word' } >设置为 word</Button>
  36. <Button type="primary" style={{marginLeft: 8}}
  37. onClick={() => {
  38. if(state.inputVal === 'word'){
  39. state.inputVal = 'hello'
  40. }else{
  41. state.inputVal = 'word'
  42. }
  43. }} >切换</Button>
  44. </div>
  45. <div style={{marginTop: 8}}> 对数组进行操作:{JSON.stringify(state.arr)}</div>
  46. <div style={{margin: '8px 0', display: 'flex',justifyContent: 'flex-start'}}>
  47. <Button type="primary" onClick={() => state.arr.push(Math.floor(Math.random() * 100))} >push</Button>
  48. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.arr.pop()} >pop</Button>
  49. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.arr.shift()} >shift</Button>
  50. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.arr.unshift(Math.floor(Math.random() * 100))} >unshift</Button>
  51. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.arr.reverse()} >reverse</Button>
  52. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.arr.sort()} >sort</Button>
  53. </div>
  54. <div style={{fontWeight: 'bold', marginTop: 8}}>计算属性:</div>
  55. <div style={{marginTop: 8}}>数量:{ state.bugsCount } 个</div>
  56. <div style={{margin: '8px 0'}}>
  57. <form
  58. onSubmit={(e) => {
  59. state.bug ? state.addBug(state.bug) : state.addBug('domesy')
  60. state.bug = '';
  61. e.preventDefault();
  62. }}
  63. >
  64. <input type="text" value={state.bug} onChange={(e) => (state.bug = e.target.value)} />
  65. <button type="submit" style={{marginLeft: 8}} >增加</button>
  66. <Button type="primary" style={{marginLeft: 8}} onClick={() => state.bugs.pop()}>删除</Button>
  67. </form>
  68. </div>
  69. <ul>
  70. {
  71. state.bugs.map((bug:any, index:number) => (
  72. <li key={index}>{bug}</li>
  73. ))
  74. }
  75. </ul>
  76. </>
  77. );
  78. };
  79. export default Mock;