Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

你们使用过哪些自定义Hook函数?可以分享一波吗?show you code... #1

Open
myprelude opened this issue Jul 5, 2019 · 2 comments

Comments

@myprelude
Copy link
Owner

myprelude commented Jul 5, 2019

一个函数解决 组件中的 setInterval 的问题

function useInterval(callback,time=300){
    const intervalFn = useRef(); // 1
    useEffect(()=>{
        intervalFn.current = callback;  // 2
    })
    useEffect(()=>{
        const timer = setInterval(()=>{
            intervalFn.current()
        },time)
        return ()=>{ clearInterval(timer) }
    },[time])  // 3
}
  • 1.通过useRef创建一个对象;
  • 2.将需要执行的定时任务储存在这个对象上;
  • 3.将time作为第二个参数是为了当我们动态改变定时任务时,能过重新执行定时器。

开发中使用:

useInterval(() => {
    // you code
}, 1000);

更新日期:2019/7/12

上次我提交了自己的自定义uesInterval很荣幸有机会使用在项目,在使用过程中发现:这个useInterval虽然可以满足一部分需求,但是如果涉及到需要自己清除定时任务时就很无力了,那我们继续改造一波~~

function useInterval(callback,time=300){
    // const intervalFn = useRef();   [1]
    const intervalFn = useRef({}); 
    useEffect(()=>{
        //   intervalFn.current = callback;  [2]
        intervalFn.current.callback = callback;  
    })
    useEffect(()=>{
        // const timer = ......   [3]
        intervalFn.current.timer = setInterval(()=>{
            intervalFn.current()
        },time)
        //  return ()=>{ clearInterval(timer) }   [4]
        return ()=>{ intervalFn.current.timer && clearInterval(intervalFn.current.timer) }
    },[time])  
    return intervalFn.current.timer  //  [5]
}
  • [1]:通过 useRef 储存一个对象
  • [2]:将callback直接赋值到对象上
  • [3]:将 定时器也挂载到对象上
  • [4]: 清除定时器前先判断定时器是否存在(我们有可能已经清理定时器了)
  • [5]:返回存放定时器(方便调用时清理)

开发时使用

const timer = useInterval(()=>{
    // you code ...
})
clearInterval(timer)

这里是体验地址

更新:2019/7/12

想到每次都要用clearInterval就不是很爽,改造一波让我们不关心clearInterval

function useInterval(){
    // ......
    return {
            clear:()=>{
                    intervalFn.current.timer && clearInterval(intervalFn.current.timer)
             }
    }
}

开发时使用

const timer = useInterval(()=>{
    // you code ...
})
timer.claer() // 直接清理 

这样改造下来是不是清爽许多,如果是要实现useTimeout呢?我们直接将上面代码中 setInterval和cleatInterval 改成 setTimeout和clearTimeout 就可以了 都是调用 clear() 来释放定时器。

@myprelude
Copy link
Owner Author

myprelude commented Aug 1, 2019

一个表单验证 Hooks useForm

import React,{useEffect,useRef,useCallback} from 'react'

function type(obj){
    return Object.prototype.toString.call(obj)
}
function isObject(obj){
    return type(obj) === '[object Object]'
}
function isArray(arr){
    return type(arr) === '[object Array]'
}
function isString(str){
    return typeof str ==='string'
} 
const Rules = {
    required:{
        pattern: /^[\s\S]*.*[^\s][\s\S]*$/,
        message:'这个是必填项'
    }
}

function formatRule(rule){
    if(isArray(rule)){
        let ruleObj = [];
        rule.forEach((list)=>{
            if( list && isString(list) ){
                if( Rules[list] ){
                    ruleObj.push(Rules[list]);
                }else{
                    console.error(`${list}  is Invalid Rules;
                     please checked rule or add ${list} in Rules`);
                }
            }
            else if( list && isObject(list) ){
                ruleObj.push(list)
            }
        })
        return ruleObj;
    }
    else if(isObject(rule)){
        return [rule]
    }
    else if( rule && isString(rule)){
        if( Rules[rule] ){
            return [Rules[rule]];
        }else{
            console.error(`${rule}  is Invalid Rules; 
             please checked rule or add ${rule} in Rules`);
            return [];
        }
    }
    else{
        return [];
    }
}

export default function useForm(){

    const inputObj = useRef({});
    const error = useRef({});

    function validate(rule){
        return (ref) => {
            if(ref){
                inputObj.current[ref.name] = {
                    ref: ref,
                    rules: formatRule(rule)
                }
                error.current[ref.name] = 
                    error.current[ref.name]?error.current[ref.name]:null;
            }
        }
    }

    function onSubmit (fn){
        let formData = {},rules = {},success = true;

        for (let k in inputObj.current) {
            formData[k] = inputObj.current[k].ref.value;
            rules[k] = inputObj.current[k].rules;
        }

        for (let k in rules) {
            error.current[k] = [];
            rules[k].forEach((item)=>{
                if( item.pattern ){ 
                    success && (success = item.pattern.test(formData[k]));
                    if(!item.pattern.test(formData[k])){
                        error.current[k].push(item.message)
                    }
                }
            })
        }

        fn && fn({ success, data:formData, error:{...error.current} })
    }

    function resetError(target,fn){
        return ()=>{
            if(target){
                error.current[target] && (error.current[target] = {});
            }else{
                error.current = {};
            }
            fn && fn({...error.current})
        }
    }

    return { validate, onSubmit, resetError }
}

使用Demo

function App (){
    const { validate, onSubmit, resetError } = useForm();  //  [1]
    const [errorMsg,setError] = useState({});
   return (
    <>
      <form>
        <input
          name="fristName"
          placeholder="请输入姓"
          onChange={resetError("fristName", setError)}
          ref={validate([
            "required",
            { pattern: /[a-zA-Z]/, message: "请输入英文字母" }
          ])}
        />
        <p>{errorMsg.fristName && errorMsg.fristName[0]}</p>
        <input
          name="lastName"
          placeholder="请输入名"
          ref={validate("required")}
        />
        <p>{errorMsg.lastName && errorMsg.lastName[0]}</p>
        <input
          name="age"
          placeholder="请按提示输入"
          ref={validate([
            "required",
            { pattern: /\d+/, message: "请输入数字" },
            "tel"
          ])}
        />
        <p>{errorMsg.age && errorMsg.age[0]}</p>
      </form>
      <div
        className="submit"
        onClick={() => {
          onSubmit(submit);
        }}
      >
        提交
      </div>
    </>
  );
    function submit(data){
        if(data.success){
            console.log(data.data)
        }else{
            setError(data.error)
        }
    }
}

使用说明

  • 首先import useForm hooks
// 如上 【1】
const { validate, onSubmit, resetError } = useForm(); 
  • validate:用来注册需要验证的input
validate(param)
param 字符串 如: validate('required') 标识用 内部提供的 required规则验证
param 对象 ; validate({pattern:/\d+/,message:"请输入数字"}) 自定义提供验证逻辑和信息
param 数组 如:validate(['required',{pattern:/\d+/,message:"请输入数字"}])要同时符合两个验证规则
  • onSubmit :提交时操作返回验证的结果和输入的数据
onSubmit (data=>{
    data 格式为:
   {
        success:true/false // 是否验证通过
        data:{ }   // 输入的数据
        error:{  }  //  错误信息提示
   }
})
  • resetError: 更新错误信息函数
resetError('',()=>{})
// 第一个参数是 需要清除name  传空则全部清除
// 第二个是 清除后的回调

注意:这里input必须要有唯一的 name 如 ;因为useForm 需要使用到 这个name来构建

更新 -- 添加自定义规则逻辑 【2019/8/1 19:41】

export default function useForm(rule){
    Rules = Object.assign({},Rules,rule||{})
    //  ...
}

使用

 const { validate, onSubmit, resetError } = useForm({
        tel:{
              pattern:/^1[3456789]\d{9}$/,
              message:'请填写正确的电话号码'
         }
 });
// html 部分
 <input name="age" 
            ref={
                   validate(['required',{pattern:/\d+/,message:"请输入数字"},'tel'])
            }
 />  

我们可以通过在调用 useForm时 提供参数来自定义规则。
--点击这里体验地址--

@webMasterMrBin
Copy link

一些通用场景的hook 社区都有成熟的hook库 react-use啥的
一般偏业务的hook 才会在项目里抽出来自己写

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants