如何在Next.js中渲染动态获取的第三方emoji-mart组件?
问题:React中如何动态加载emoji-mart组件以避免增大包体积
我正在使用emoji-mart这款npm表情选择器包,其压缩并gzip后的大小约25Kbs。为避免增大包体积和初始加载时间,我希望仅在需要时动态获取该组件。
在文档中可找到通过CDN动态获取的方式(如下代码片段),但该方式返回HTML元素,而React无法将对象作为子元素渲染,我想了解如何正确动态获取并渲染该组件。
import { Picker } from 'emoji-mart' new Picker({ data: async () => { const response = await fetch( 'https://cdn.jsdelivr.net/npm/@emoji-mart/data', ) return response.json() } })
我尝试过Next.js动态导入,但认为它目前仅支持本地组件;还考虑过将HTML字符串化后使用dangerouslySetInnerHTML,但这方法过于粗糙。
解决方案
1. Next.js场景:使用官方动态导入(支持npm包)
你之前对Next.js动态导入的理解有误——它完全支持npm包的按需加载,并非仅局限于本地组件。可以通过next/dynamic动态导入emoji-mart的React组件,同时禁用SSR(表情选择器通常不需要服务端渲染)来优化:
import dynamic from 'next/dynamic'; import { useState } from 'react'; // 动态加载Picker组件,关闭SSR,设置加载占位 const EmojiPicker = dynamic( () => import('emoji-mart').then(mod => mod.Picker), { ssr: false, loading: () => <div>加载表情选择器...</div> } ); function EmojiPickerTrigger() { const [showPicker, setShowPicker] = useState(false); return ( <div> <button onClick={() => setShowPicker(!showPicker)}> {showPicker ? '关闭选择器' : '打开表情选择器'} </button> {showPicker && ( <EmojiPicker data={() => fetch('https://cdn.jsdelivr.net/npm/@emoji-mart/data').then(res => res.json())} /> )} </div> ); } export default EmojiPickerTrigger;
这种方式会在用户触发显示选择器时,才会加载emoji-mart的代码和表情数据,完全避免初始加载时的体积损耗。
2. 普通React项目:原生动态导入+状态管理
如果是常规React项目,直接用原生import()语法结合状态管理实现按需加载:
import { useState, useEffect } from 'react'; function EmojiPickerWrapper() { const [PickerComponent, setPickerComponent] = useState(null); useEffect(() => { // 组件挂载后才加载emoji-mart import('emoji-mart').then(({ Picker }) => { setPickerComponent(Picker); }); }, []); if (!PickerComponent) { return <div>加载中...</div>; } return ( <PickerComponent data={() => fetch('https://cdn.jsdelivr.net/npm/@emoji-mart/data').then(res => res.json())} /> ); } // 按需使用示例 function App() { const [showPicker, setShowPicker] = useState(false); return ( <div> <button onClick={() => setShowPicker(!showPicker)}>切换表情选择器</button> {showPicker && <EmojiPickerWrapper />} </div> ); } export default App;
3. 为什么不用原生DOM版本?
你文档里看到的new Picker()是emoji-mart的原生DOM操作版本,并非React组件,所以返回的是HTML元素,无法直接在React的JSX中渲染。上面两种方案都使用了官方封装的React组件,完全适配React的渲染逻辑,不需要用dangerouslySetInnerHTML这种不安全的方式。
内容的提问来源于stack exchange,提问作者Sarthak kundra
相关产品推荐
相关产品推荐

