阅读 275

React - 自定义Hooks - useCompositions

前言

在工作中时常会遇到这样一个场景:页面上方有一个搜索框,根据搜索关键字去请求接口获取列表数据,将数据渲染至下方列表中做展示。

这时我们会遇到一个问题:在输入框中输入中文时,会发现每输入一个中文拼音字符,都会触发一次 Input 输入框 onChange 事件,进而触发请求接口逻辑;

这显然不是我们所期望的,我们希望可以在输入中文拼音并按下空格选择中文后,触发接口请求。

这时我们就需要使用 onCompositionStart 和 onCompositionEnd 事件来处理中文拼音的触发请求时机。

下面将介绍两种解决中文拼音输入问题的方式:

  • 普通方式;

  • 自定义 Hook 方式(基于普通方式封装为一个 Hook 实现功能复用)。

普通方式:

Input 基础示例:

import React { useState, useRef } from 'react'; const App = () => {     const [value, setValue] = useState<string>('');          const onChange = (event: React.ChangeEvent<TInputElement>) => {         setValue(event.target.value);         fetchListDataApi(); // 伪代码,强调用做请求数据的独立方法     }          return (         <Input value={value} onChange={onChange} />     ) } 复制代码

定义 compositionLock:

compositionLock 是一个 boolean 值,用于在 onCompositionStart 和 onCompositionEnd 中控制输入中文拼音的一个

这里我们借助 useRef 对数据持久化的特性,来保存 compositionLock 值。

const App () => {     // ...     const compositionLockRef = React.useRef<boolean>(false);          // ... } 复制代码

onCompositionStart 和 onCompositionEnd 事件定义:

input 元素提供了 onCompositionStart 和 onCompositionEnd 这两个 DOM 事件,在事件对象 event 中可以根据 type 区分是 start 还是 end,因此可以复用一个处理函数。

完整代码如下:

import React { useState, useRef } from 'react'; const App = () => {     const [value, setValue] = useState<string>('');     const compositionLockRef = React.useRef<boolean>(false);          const onChange = (event: React.ChangeEvent<TInputElement>) => {         setValue(event.target.value); // 将中文拼音更新到 state 和 view 中         if (compositionLockRef.current) return; // 允许输入中文时更新视图 value,但不触发数据逻辑         fetchListDataApi(event.target.value); // fetch API     }          const onComposition = (event: React.CompositionEvent<TInputElement>) => {         if (event.type === 'compositionend') {           compositionLockRef.current = false;           fetchListDataApi(event.currentTarget.value); // fetch API         } else {           compositionLockRef.current = true;         }     }          return (         <Input              value={value}              onChange={onChange}             onCompositionStart={onComposition}             onCompositionEnd={onComposition}         />     ) } 复制代码

自定义 Hook - useCompositions

从上面的实现可以看到,思路也比较简单清晰;

但试想:项目中有多处都用到了 input 搜索请求,显然 Copy 这样的代码不是最可取的选择,能不能有一种方式可以做到复用 onCompositionStart 和 onCompositionEnd 的处理逻辑呢?于是,useCompositions 诞生!

我们可以编写一个 Hook,由它来提供 compositionLock 锁和 onComposition 方法,外边不关注它的具体实现,只需要将 onComposition 方法绑定到 input 元素的 onCompositionStart 和 onCompositionEnd 事件上即可。

实现:

import React from 'react'; type TInputElement = HTMLInputElement | HTMLTextAreaElement; export interface CompositionsResult {   value: string,    setValue: React.Dispatch<React.SetStateAction<string>>,   onChange: (event: React.ChangeEvent<TInputElement>) => void,   onComposition: (event: React.CompositionEvent<TInputElement>) => void, } function useCompositions(   defaultValue: string,   onSearch?: (value: string) => void, ): CompositionsResult{   const [value, setValue] = React.useState<string>(defaultValue);   const compositionLockRef = React.useRef<boolean>(false);   const handleSearch = (value: string) => {     onSearch && onSearch(value);   }   const onChange = (event: React.ChangeEvent<TInputElement>) => {     const newValue = event.target.value;     setValue(newValue);     if (compositionLockRef.current) return; // 允许输入中文时更新视图 value,但不触发数据逻辑     handleSearch(newValue);   }   const onComposition = (event: React.CompositionEvent<TInputElement>) => {     if (event.type === 'compositionend') {       compositionLockRef.current = false;       handleSearch(event.currentTarget.value);     } else {       compositionLockRef.current = true;     }   }   return {     value,     setValue,     onChange,     onComposition   } } export default useCompositions; 复制代码

使用:

const App = () => {     // useDebounce 用于处理防抖的 hook     const handlerSearch = useDebounce((val: string) => {         fetchListDataApi(val); // fetch API     });     const { value, onChange, onComposition } = useCompositions('', handlerSearch);          return (         <Input              value={value}              onChange={onChange}             onCompositionStart={onComposition}             onCompositionEnd={onComposition}         />     ) }


作者:明里人
链接:https://juejin.cn/post/7032960513025769508


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐