自定义hook的一次实践

584 阅读2分钟

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战

Hope is a good thing, maybe the best of things. And no good thing ever dies—— 《The Shawshank Redemption》

前言

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。通过自定义 Hook,可以将组件逻辑提取到可重用的函数中。

最近在做一个业务代码,在一个 RadioGroup 的每个 Radio 后面渲染一个额外的 Field,作为 Form 的一个 FormItem,需要支持 FormItem 的自定义校验(包含错误状态的转换和错误信息定的显示)。而且在一个页面中会出现多个类型的 FormItem,这样就要保证每个组件内部的状态唯一性。

因为我们组件是做到复用的,所以就想到了使用 自定义 Hook 去拆解这一步业务逻辑。

业务代码实现

  • 自定义Hook逻辑 将动态渲染的 FormItem 的校验逻辑抽离出来,将每个表单的校验状态和错误信息提取到一个公共的数据中
import { useState, useCallback }from 'react';


export function useValidator() {
  // 定义错误状态的集合
  const [status, setValidateStatus] = useState({});
  // 定义错误信息的集合
  const [errorMessage, setErrorMessage] = useState({});

  // 当表单的FormItem的值发生变化,调用 valueChange 方法去修改FormItem对应的状态和错误信息
  const valueChange = useCallback((name, value) => {
    if(value) {
      setValidateStatus({...status, [name]: ''})
      setErrorMessage({...errorMessage, [name]: ''})
    } else {
      setValidateStatus({...status, [name]: 'error'})
      setErrorMessage({...errorMessage, [name]: '请设置有效值'})
    }
  }, [])
  // hook对外抛出状态和值改变的调用方法
  return [status, errorMessage, valueChange];
}

  • 组件引入自定义 hook
import { useValidator } from './hook'

export default (props: IProps) => {
  const [form] = Form.useForm();
  此处省略若干代码....
  
  // 在组建顶层,调用最定义hook
  const [status, errorMessage, valueChange] : any = useValidator();
  

  .....
  
   const fields = allFields
      .filter(ele => names.includes(ele.name))
      .map(field => {
        const currentName = field.name;
        const itemField = { ...field, disabled: readOnly || disabled };
        const editableFieldChange = async value => {
          // 使用受控组件的方式
          onValueChange(currentName, value);
          当值改变的时候调用hook的方法,去修改状态
          valueChange(currentName, value)
        };
        return (
          <FormItem
            validateStatus={status[currentName]}
            help={errorMessage[currentName]}
          >
            <EditableField
              page={props?.page}
              onChange={editableFieldChange}
              field={itemField}
              value={get(formData, currentName)}
            />
          </FormItem>
        );
      });
}

自定义hook的注意事项

  • 自定义 Hook 是一种自然遵循 Hook 设计的约定,而并不是 React 的特性。
  • 自定义 Hook 必须以 “use” 开头
  • 在两个组件中使用相同的 Hook 不会共享 state。

自定义 Hook 是一种重用状态逻辑的机制(例如设置为订阅并存储当前值),所以每次使用自定义 Hook 时,其中的所有 state 和副作用都是完全隔离的。

  • 每次调用 Hook,它都会获取独立的 state
  • 不要在循环条件或者嵌套中使用,要在组件最顶层使用

结语

如果这篇文章帮到了你,欢迎点赞👍和关注⭐️。

文章如有错误之处,希望在评论区指正🙏🙏

欢迎关注我的微信公众号,一起交流技术,微信搜索 🔍 :「 五十年以后