You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:01:00