简化React Hook的5种方法

开发 前端
在编写自定义Hook时,很容易产生过于复杂的解决方案。这有时会导致不稳定的行为,创建无用的重新渲染,或者只是使其更难维护。考虑到这一点,我想分享5种我发现的帮助简化定制Hook的方法。

在编写自定义Hook时,很容易产生过于复杂的解决方案。这有时会导致不稳定的行为,创建无用的重新渲染,或者只是使其更难维护。考虑到这一点,我想分享5种我发现的帮助简化定制Hook的方法。

简化React Hook的5种方法

1. 减少 useState 数量

当你使用hook进行开发时,很容易使用过多的 useState 调用,或者将所有的状态缩减为单一的、过于复杂的 useState。提高hook的可读性的最好方法之一就是优先考虑你的 useState 调用。我喜欢在我写的钩子中遵循一些关于状态实现的规则。

(1) 优先考虑易读性

我更喜欢将状态读取为对象,而不是使用多个具有简单值的 useState 命令。使用更少的 useState 命令也会让你的钩子的返回更容易,并且在组件中的实现更直接。虽然这是我的偏好,但代码是一个非常个人化的东西,也是非常有表现力的。我写代码时的第一条规则是优先考虑可读性,遵循这个规则会让你的代码更容易维护,迫使你去思考你所写的东西,并让别人更容易遵循你的代码。如果这是你从这个文章中带走的唯一东西,那么我已经完成了我的工作。

(2) 评估状态对象的内容

组件从一开始就没有被完美地规划过,随着组件的增长,你的 useState 中包含的属性可能也会变得越来越复杂。在整个开发周期中,我强烈建议评估你的 useState 调用的内容,以确定将状态部分分成其他 useState 调用是否有意义。你可能想按功能或类型对状态值进行分组。一般来说,我喜欢把状态数据按照我认为通常会一起更新的属性来分组,或者按照状态属性的功能来分组,比如数据和视图属性。

2. 利用你的Hook返回

当我刚开始写自定义Hook时,很容易遵循类似于默认的 useState 钩子的返回样式。虽然这并不是坏事,但在函数之上使用一个返回数组来返回多个状态变量,会很麻烦。想象一下,除了处理数据选择的函数外,还可以返回2个不同的状态变量(1个是数据状态,1个是视图状态)的钩子,用数组风格的返回方式编写,它可能看起来像这样。

  1. function useBasicHook() { 
  2.   const [dataState, setDataState] = useState({ 
  3.     serverData: {}, 
  4.     selections: {} 
  5.   }); 
  6.   const [viewState, setViewState] = useState({ 
  7.     menuExpanded: false, 
  8.     submitFormData: {} 
  9.   }) 
  10.    
  11.   const toggleMenuExpand = () => { 
  12.     setViewState({ 
  13.       menuExpanded: !viewState.menuExpanded, 
  14.       submitFormData: viewState.submitFormData 
  15.     }) 
  16.   } 
  17.    
  18.   return [dataState, viewState, toggleMenuExpande]; 
  19.  
  20. function BasicComponent(){ 
  21.   const [dataState, viewState, toggleMenuExpand] = useBasicHook(); 
  22.    
  23.   return <div> 
  24.     </div> 

看看这个hook,很容易看出,如果在返回中添加额外的函数或变量,hook的实现会很快失控。如果你不小心破坏了数组的顺序,或者用不正确的名称,会造成额外的混乱和可能的错误。我们可以通过更新hook返回一个对象来防止这种情况的发生,就像这样。

  1. function useBasicHook() { 
  2.   const [dataState, setDataState] = useState({ 
  3.     serverData: {}, 
  4.     selections: {} 
  5.   }); 
  6.   const [viewState, setViewState] = useState({ 
  7.     menuExpanded: false, 
  8.     submitFormData: {} 
  9.   }) 
  10.    
  11.   const toggleMenuExpand = () => { 
  12.     setViewState({ 
  13.       menuExpanded: !viewState.menuExpanded, 
  14.       submitFormData: viewState.submitFormData 
  15.     }) 
  16.   } 
  17.    
  18.   return { 
  19.     dataState: dataState, 
  20.     viewState: viewState, 
  21.     toggleMenuExpand: toggleMenuExpand 
  22.   }; 
  23.  
  24. function BasicComponent(){ 
  25.   const state = useBasicHook(); 
  26.   // or 
  27.   // const {dataState, viewState, toggleMenuExpand} = useBasicHook(); 
  28.    
  29.   return <div> 
  30.     </div> 

将返回值转换为对象还有其他好处,包括:

  • 如果hook在多个组件之间共享或作为库共享,则在更新后提高hook版本的兼容性;
  • 在使用Hook在组件顶部提供相同级别的Hook API时,仍然可以解构对象。

还有一件很酷的事情,你可以用你的钩子返回,就是在你的状态中创建基于组件工厂函数的小状态。这提供了一种很好的方式,可以将组件构建器共享给实现钩子的组件,而无需将状态公开给该组件。

3. 使用合并钩子简化 setState 调用

在React中使用类而不是基于函数的组件进行开发,当涉及到状态管理时,确实有一些开箱即用的优势,对我来说,最主要的是旧状态与新状态的合并。React Docs for State提供了React.Component中内置的状态合并功能的良好示例。虽然该功能没有直接内置到钩子中,但我们可以通过一个简单的自定义钩子来复制这种行为,它可以替换我们的 useState 调用,给我们同样的行为。

  1. function useMergeState(initialState) { 
  2.   const [state, setState] = useState(initialState); 
  3.   // 使用 useRef 来改进异步调用 setState 时的功能。 
  4.   const stateRef = useRef(state); 
  5.  
  6.   function setRefState(newState) { 
  7.       stateRef.current = newState
  8.       return setState(newState); 
  9.   } 
  10.  
  11.   function mergeState(newState) { 
  12.     var finalState = newState
  13.     /** 
  14.      * 判断状态数据类型是否匹配,如果匹配,则继续合并, 
  15.      * 如果不匹配,则抛出一个控制台警告,用新的状态覆盖。 
  16.      */ 
  17.     if (typeof stateRef.current !== typeof newState) { 
  18.       console.warn( 
  19.         "useMergeState warning: 状态数据类型不匹配,用新的状态覆盖状态。" 
  20.       ); 
  21.       finalState = newState
  22.     } else { 
  23.       /** 
  24.        * 在此处理合并 
  25.        */ 
  26.       if (typeof stateRef.current == "object" && !Array.isArray(stateRef.current)) { 
  27.         // 现有状态是一个对象,继续尝试合并 
  28.         if (typeof newState == "object" && !Array.isArray(newState)) { 
  29.           finalState = { ...stateRef.current, ...newState }; 
  30.         } 
  31.       } 
  32.     } 
  33.  
  34.     return setRefState(finalState); 
  35.   } 
  36.  
  37.   return [stateRef.current, mergeState]; 

4. 考虑拆分Hook

无论组件的复杂程度如何,我总是建议使用自定义钩子;然而,在构建自定义钩子时,将一个过于复杂的钩子分割成多个较简单的钩子是非常有用的。在我的项目中,我喜欢根据功能来拆分钩子逻辑,比如说,把一个钩子拆成逻辑上的状态子集,比如数据/Web API交互的钩子和显示状态的单独的钩子,可能会有好处。回想一下钩子返回部分的例子钩子,这样拆开来可能会有帮助。

  1. function useDataHook() { 
  2.   const [dataState, setDataState] = useState({ 
  3.     serverData: {}, 
  4.     selections: {} 
  5.   }); 
  6.    
  7.   return dataState; 
  8.  
  9. function useDisplayHook() { 
  10.   const [viewState, setViewState] = useState({ 
  11.     menuExpanded: false, 
  12.     submitFormData: {} 
  13.   }) 
  14.    
  15.   const toggleMenuExpand = () => { 
  16.     setViewState({ 
  17.       menuExpanded: !viewState.menuExpanded, 
  18.       submitFormData: viewState.submitFormData 
  19.     }) 
  20.   } 
  21.    
  22.   return { 
  23.     viewState: viewState, 
  24.     toggleMenuExpand: toggleMenuExpand 
  25.  
  26. function BasicComponent(){ 
  27.   const data = useDataHook(); 
  28.   const display = useDisplayHook(); 
  29.    
  30.   return <div> 
  31.     </div> 

拆分后的示例挂钩

[[328037]]

5. 评估 useEffect 调用,以防止不必要的重新渲染

useEffect钩子非常有用,但是如果使用不当,可能会导致过度渲染。查看自定义钩子时,值得评估你的useEffect调用。我喜欢遵守以下经验法则:

如果一个 useEffect 在同一个钩子作用域中监听状态变量,那么这个效果不应该更新状态本身。

如果你有多个useEffect语句在侦听同一组变量,请考虑将它们组合在一起。

尽管结合使用 useEffects 有助于减少重新渲染次数,但首先要优先考虑代码的可读性。

 

责任编辑:赵宁宁 来源: 今日头条
相关推荐

2020-05-26 11:39:05

WebReact组件

2016-06-28 10:19:31

云计算云安全

2020-09-01 09:56:26

云端云计算云服务

2024-11-04 12:38:52

2022-08-01 07:56:23

React Hook开发组件

2020-07-24 09:56:12

React开发数据

2019-08-22 07:24:25

2021-02-25 10:46:21

云计算云服务器云安全

2023-06-08 09:00:00

2022-05-24 14:37:49

React条件渲染

2018-11-01 10:10:35

网络安全网络攻击网络威胁

2021-03-21 22:23:38

云计算数据中心IT

2020-06-09 11:16:42

云计算云平台工具

2010-12-01 09:04:59

PHP开发

2010-01-27 09:53:37

2021-02-05 08:03:52

Java

2017-11-22 14:45:59

物联网数据数据分析

2021-03-02 13:53:50

人工智能智慧城市Infratech

2020-01-16 18:33:24

安全数据网络

2020-07-06 14:00:01

Pandas连接参数
点赞
收藏

51CTO技术栈公众号