React+TS使用emoji-mart时无法选中表情触发onSelect回调问题
问题原因
回调不触发是三个问题叠加导致的:
useEffect依赖项直接写了[props],每次父组件重渲染都会生成新的props对象引用,导致effect反复执行、重复创建Picker实例,旧实例的事件绑定被覆盖,新实例没有正确完成事件挂载。- 传给Picker构造函数的
ref参数传了React的ref包装对象,而emoji-mart要求这个参数接收真实的DOM节点,导致事件监听根本没有绑定到渲染出来的元素上。 - ref类型标注错误,容器是普通div元素,标注成
HTMLInputElement会导致TS校验出现隐性逻辑问题。
修复方法
修改自定义EmojiPicker组件的逻辑即可,修复后代码如下:
import React, { useEffect, useRef } from "react" import data from "@emoji-mart/data" import { Picker, PickerProps } from "emoji-mart" const EmojiPicker = (props: PickerProps) => { // 修正ref类型,同时新增实例存储ref避免重复初始化 const containerRef = useRef<HTMLDivElement>(null) const pickerRef = useRef<Picker | null>(null) useEffect(() => { // 容器未挂载时不执行初始化 if (!containerRef.current) return // 已经初始化过实例就跳过,避免重复创建 if (pickerRef.current) return // 传入真实DOM节点,而非ref包装对象 pickerRef.current = new Picker({ ...props, data, ref: containerRef.current }) // 组件卸载时清空实例引用,避免内存泄漏 return () => { pickerRef.current = null } // 移除props依赖,仅在组件首次挂载时初始化一次Picker }, []) return <div ref={containerRef} /> } export default EmojiPicker
补充说明:如果需要动态修改Picker配置(比如切换主题、修改回调函数),不要重复创建Picker实例,可通过picker实例暴露的方法单独更新对应属性即可。
内容的提问来源于stack exchange,提问作者Oren Papa
相关产品推荐
相关产品推荐

