# react-use-echarts
> [中文](./README-zh_CN.md) | [English](./README.md)
[](https://www.npmjs.com/package/react-use-echarts)
[](https://www.npmjs.com/package/react-use-echarts)
[](https://github.com/chensid/react-use-echarts/actions/workflows/ci.yml)
[](https://codecov.io/gh/chensid/react-use-echarts)
[](https://github.com/chensid/react-use-echarts/issues)
[](https://github.com/chensid/react-use-echarts/pulls)
[](https://github.com/chensid/react-use-echarts/blob/main/LICENSE.txt)
[](https://bundlephobia.com/package/react-use-echarts)
[](https://www.npmjs.com/package/react-use-echarts)
React Hooks & 组件,用于 Apache ECharts — TypeScript、自动 resize、主题、懒加载。
**[📊 在线 Demo 与交互式 Playground →](https://chensid.github.io/react-use-echarts/)**
[](https://chensid.github.io/react-use-echarts/)
## 特性
- **Hook + 组件** — 使用 `useEcharts` Hook 或声明式 `` 组件
- **TypeScript 优先** — 完整的类型定义,支持 IDE 自动补全
- **零依赖** — 除 peer 依赖外无运行时依赖
- **自动 resize** — 通过 ResizeObserver 自动处理容器尺寸变化
- **主题** — 内置 light、dark、macarons 主题,支持任意自定义主题
- **图表联动** — 连接多个图表实现同步交互
- **懒加载** — 图表进入视口时才初始化
- **StrictMode 安全** — 实例缓存基于引用计数,正确处理双重挂载/卸载
## 为什么选 react-use-echarts?
面向 **React 19 + ECharts 6** 团队的现代化、hook 优先封装。ECharts 仍是唯一事实来源 —— 你直接传 `EChartsOption`,没有需要重新学习的抽象层。
| | react-use-echarts | echarts-for-react |
| ----------- | ------------------------------------------- | ---------------------- |
| API | `useEcharts` Hook **和** `` 组件 | 仅组件 |
| 面向 | React 19 —— callback ref、StrictMode 安全 | React 16–18 时代 |
| 自动 resize | `ResizeObserver` + RAF,默认开启 | ✓ |
| 懒加载 | 内置 `lazyInit`(IntersectionObserver) | 需手写 |
| 图表联动 | 内置 `group` prop | 手动 `echarts.connect` |
| 错误路由 | `onError` 统一处理图表操作和命令式 API 错误 | 手动 try/catch |
| 格式与依赖 | ESM-only、可 tree-shake、零运行时依赖 | CJS + ESM,零依赖 |
已在用 `echarts-for-react`?大多数 props 一一对应 —— 见 [从 echarts-for-react 迁移](#从-echarts-for-react-迁移)。
## 环境要求
- React 19.2+(`react` + `react-dom`)—— 内部使用 `useEffectEvent`,该 API 在 19.2 进入 stable
- ECharts 6.x
- Node.js 22+(仅构建/SSR 框架层面需要;发布产物是浏览器 ESM)
> **仅支持 CSR。** ECharts 需要真实 DOM,不支持 SSR。
>
> **1.3.0 起仅提供 ESM。** 只发布单份 ESM 产物(`dist/index.js`)。所有现代打包工具(Vite、Next.js、webpack 5+、Rspack、Parcel、Turbopack)和 Node 22+(`require(ESM)`)均可直接消费。如仍依赖 CJS-only 工具链,请固定在 `1.2.x`。
## 安装
```bash
npm install react-use-echarts echarts
# 或
yarn add react-use-echarts echarts
# 或
pnpm add react-use-echarts echarts
```
## 注册 ECharts 模块
从 v2.1 起 `react-use-echarts` 完全 modular —— 库本身不会自动注册任何图表/组件/渲染器/特性。请在应用入口(首次渲染前)调用以下其中之一:
```ts
// 最简方式 —— 注册 ECharts 内置全套(约 290KB gzip)
import { registerEchartsFull } from "react-use-echarts/preset-full";
registerEchartsFull();
```
或者,为了在生产构建中获得更好的 tree-shake 效果,只显式注册实际用到的模块 —— 参见 [Tree-shaking](#tree-shaking)。
> **原因**:现代打包器(Rolldown/Oxc、Rollup)会把 ECharts 顶层 `use([...])` 副作用调用按纯函数 DCE 掉,因为 ECharts 上游 package.json 的 `sideEffects` 字段不规范。把注册责任放在使用方,可以保证 `react-use-echarts` 在所有现代打包器下都可靠工作 —— 这与 `vue-echarts`、`nuxt-echarts`、`react-chartjs-2` 的做法一致。
## 快速开始
### 1. 注册 ECharts 一次
最快上手方式是在应用入口注册 ECharts 全量能力:
```ts
// main.tsx / index.tsx
import { registerEchartsFull } from "react-use-echarts/preset-full";
registerEchartsFull();
```
生产构建如果只渲染少量图表类型,可以稍后替换为按需 `echarts.use([...])` 注册;图表 API 不变。
### 2. 渲染图表
最简单的组件用法 — 无需手动管理 ref:
```tsx
import { EChart } from "react-use-echarts";
function MyChart() {
return (
);
}
```
图表容器必须有明确尺寸。上例直接在 `` 上设置高度;如果保留默认 `{ width: "100%", height: "100%" }`,则父容器必须有显式高度。
通过 `ref` 可访问命令式 API —— 完整列表见 [返回值](#返回值)(`setOption`、`dispatchAction`、`clear`、`resize`、`appendData`、`getDataURL`、`convertToPixel` 等)。
### 3. 直接使用 Hook
需要完全控制时,直接使用 Hook。它返回一个用于挂载到容器的 callback `ref`、响应式的 `instance` 字段,以及完整的命令式 API:
```tsx
import { useEcharts } from "react-use-echarts";
function MyChart() {
const { ref, instance, setOption, resize } = useEcharts({
option: {
xAxis: { type: "category", data: ["Mon", "Tue", "Wed", "Thu", "Fri"] },
yAxis: { type: "value" },
series: [{ data: [150, 230, 224, 218, 135], type: "line" }],
},
});
return
;
}
```
`instance` 在初始化前及销毁后为 `undefined`;通过 `useEffect([instance])` 即可订阅实时 ECharts 实例并在其上挂副作用。
图表容器必须有明确尺寸,例如 `style={{ width: "100%", height: "400px" }}`。
## 使用示例
### 主题
内置主题需在应用入口注册一次:
```tsx
import { registerBuiltinThemes } from "react-use-echarts/themes/registry";
registerBuiltinThemes();
// 内置主题
useEcharts({ option, theme: "dark" });
// 任意通过 echarts.registerTheme 注册的主题
useEcharts({ option, theme: "vintage" });
// 自定义主题对象(使用 useMemo 保持引用稳定)
const customTheme = useMemo(() => ({ color: ["#fc8452", "#9a60b4", "#ea7ccc"] }), []);
useEcharts({ option, theme: customTheme });
```
> 注意:直接通过 `echarts.registerTheme()` 注册的主题名(如上面的 `"vintage"`)可以正常使用,但由于本库无法感知这类注册,dev 环境下会触发一次性的警告。推荐改用本库导出的 `registerCustomTheme(name, config)` 按名称注册——注册会被本库跟踪,从而消除该警告。若必须使用 `echarts.registerTheme()`(例如由第三方包代为注册),只要注册发生在图表挂载之前,该警告可以安全忽略;生产构建中不会出现此警告。
### 事件处理
支持简写(函数)和完整配置(带 query/context 的对象)两种写法。已知 echarts 事件的 `params` 类型会从 `EChartsEventPayloadMap` 自动推导,无需手动断言。
```tsx
useEcharts({
option,
onEvents: {
// params 自动推导为 ECElementEvent
click: (params) => console.log("clicked", params.data),
mouseover: {
handler: (params) => console.log("hovered", params.value),
query: "series",
},
// params 自动推导为 SelectChangedPayload
selectchanged: (params) => console.log("selection changed", params),
},
});
```
自定义事件名(如通过 `echarts.registerAction()` 注册)会回退到开放索引签名,`params` 类型较宽松。若要为自定义事件获得类型化 payload,可对 `EChartsEventPayloadMap` 做 module augmentation:
```ts
declare module "react-use-echarts" {
interface EChartsEventPayloadMap {
"my-custom-action": { foo: number; bar: string };
}
}
```
### 加载状态
```tsx
const [loading, setLoading] = useState(true);
useEcharts({
option,
showLoading: loading,
loadingOption: { text: "加载中..." },
});
```
### 图表联动
为多个图表指定相同的 `group` ID,tooltip、highlight 等交互将自动同步:
```tsx
useEcharts({ option: option1, group: "dashboard" });
useEcharts({ option: option2, group: "dashboard" });
```
### 懒加载
延迟初始化图表,直到元素滚动进入视口:
```tsx
useEcharts({ option, lazyInit: true });
// 自定义 IntersectionObserver 配置
useEcharts({
option,
lazyInit: { rootMargin: "200px", threshold: 0.5 },
});
```
> 注意:懒加载是一次性锁存——「懒」指「首次可见前推迟初始化」,而非持续追踪可见性。一旦元素相交过,图表在该 Hook 的生命周期内保持已初始化:更换容器 DOM 节点或将 `lazyInit` 关闭后再开启都不会重新观察。若需重新进入推迟状态,请重新挂载组件。
### Tree-shaking
库已完全 modular,可按需选择注册粒度:
**第 1 档 —— 全套注册(开发 / 原型)**:一行代码,约 290KB gzip:
```ts
import { registerEchartsFull } from "react-use-echarts/preset-full";
registerEchartsFull();
```
**第 2 档 —— 按需注册(推荐用于生产)**:只注册实际渲染的模块,打包器会 tree-shake 掉其余 ECharts:
```ts
import * as echarts from "echarts/core";
import { LineChart } from "echarts/charts";
import { GridComponent, TooltipComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
echarts.use([LineChart, GridComponent, TooltipComponent, CanvasRenderer]);
```
可运行示例参见 [`examples/selective-registration/SelectiveRegistrationChart.tsx`](./examples/selective-registration/SelectiveRegistrationChart.tsx)。
**第 3 档 —— 仅 webpack 旧方案**:webpack 对 ECharts 不规范的 `sideEffects` 字段较宽容,所以 `import "echarts";` 在 webpack 应用里仍可工作;但在 Rolldown/Vite/Rollup 下会**静默失败**(图表始终不渲染,控制台抛 zrender 空 painter registry 引起的 `TypeError`)。请改用第 1 或第 2 档。
> ECharts 维护单一全局 registry,`echarts.use([...])` 与 `registerEchartsFull()` 可自由组合,任意顺序,任意位置;但必须在首次 `useEcharts()` 渲染**之前**完成。
### 在 Next.js(App Router)中使用
默认包入口、`preset-full` 与 `themes/registry` 已标注 `"use client"`,因此
即便在 React Server Component 中 import 也不会把 ECharts 打入 server bundle。
把图表封装到自己的客户端组件里,再从任意 Server Component 直接 import:
```tsx
// app/components/MyChart.tsx
"use client";
import { EChart } from "react-use-echarts";
import { registerEchartsFull } from "react-use-echarts/preset-full";
registerEchartsFull();
export function MyChart() {
return (
);
}
```
```tsx
// app/page.tsx(Server Component)—— 直接 import 客户端组件
import { MyChart } from "./components/MyChart";
export default function Page() {
return ;
}
```
> **仅 Pages Router:** 如果需要在 `getServerSideProps` / `getStaticProps`
> 的页面中强制仅在客户端渲染,可使用
> `dynamic(() => import("./components/MyChart").then((m) => m.MyChart), { ssr: false })`。
> 在 **App Router** 中,Server Component 不允许使用 `next/dynamic` 配合
> `ssr: false`——`"use client"` 指令已经能处理同样的需求。
## 注意事项
- **容器必须有明确尺寸** — 高度为 0 时图表不可见;请为容器设置 `height`(以及 `width` 如果不是 100%)。
- **不要忘记注册 ECharts 模块** — `useEcharts()` 在 ECharts 全局 registry 上初始化实例,所以图表/组件/渲染器/特性必须先注册(通过 `registerEchartsFull()` 或 `echarts.use([...])`)。忘记注册通常表现为 `Renderer 'undefined' is not imported` 报错,或图表静默不渲染;参见 [注册 ECharts 模块](#注册-echarts-模块)。开发模式下若 init 抛出 `… is not a constructor`,库还会打印一次性提示指向此处。
- **`onEvents` 引用应保持稳定** — 每次渲染传入新的 `onEvents` 对象会触发全量重新绑定。使用 `useMemo` 缓存(或提升到模块级)。
- **不要让多个 `useEcharts` 共享同一个 DOM 元素** — 实例缓存会复用同一个 ECharts 实例并在开发模式下打印警告;多个 hook 的更新会互相覆盖。
- **`initOpts` 和自定义 `theme` 对象引用变化会重建实例** — 传递 memoized 对象或模块级常量,除非确实需要重建。
- **StrictMode 安全** — 双挂载/卸载由带引用计数的实例缓存正确处理。
## API 参考
### `` Props
封装了 `useEcharts` 的声明式组件。接受所有 Hook 选项作为 props,另外支持:
| Prop | 类型 | 默认值 | 说明 |
| ----------- | --------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `style` | `React.CSSProperties` | `{ width: '100%', height: '100%' }` | 容器样式(与默认样式合并) |
| `className` | `string` | — | 容器 CSS 类名 |
| `ref` | `Ref` | — | 以 `EChartHandle`(`Omit` —— 容器 ref 由 `` 自管,不再暴露给外部)暴露命令式 API |
### `useEcharts(options)`
#### Options
| 选项 | 类型 | 默认值 | 说明 |
| --------------- | ------------------------------------- | ---------- | --------------------------------------------------------------------------------------------------- |
| `option` | `EChartsOption` | (必需) | ECharts 配置选项 |
| `theme` | `string \| object` | — | 任意已注册主题名或自定义主题对象 |
| `renderer` | `'canvas' \| 'svg'` | `'canvas'` | 渲染器类型 |
| `lazyInit` | `boolean \| IntersectionObserverInit` | `false` | 基于 IntersectionObserver 的懒加载 |
| `group` | `string` | — | 图表联动组 ID |
| `setOptionOpts` | `SetOptionOpts` | — | `setOption` 的默认选项 |
| `showLoading` | `boolean` | `false` | 是否显示加载指示器 |
| `loadingOption` | `object` | — | 加载指示器配置 |
| `onEvents` | `EChartsEvents` | — | 事件处理器(`fn` 或 `{ handler, query?, context? }`) |
| `autoResize` | `boolean` | `true` | 通过 ResizeObserver 自动 resize |
| `initOpts` | `EChartsInitOpts` | — | 传递给 `echarts.init()`(devicePixelRatio、locale 等) |
| `onError` | `(error: unknown) => void` | — | 图表操作和命令式 API 的错误处理回调。未提供时 effect 内失败走 `console.error`,命令式方法则直接抛出 |
#### 返回值
> 优先使用声明式 props(`option`、`theme`、`showLoading` 等),命令式方法仅在 props 未覆盖的场景下使用——例如导出图片、坐标转换、流式追加等。
> 实例未初始化时所有方法均为 no-op 或返回安全默认值。实例抛出错误时:提供 `onError` 时路由错误并返回默认值;未提供 `onError` 时直接重新抛出(读取方法亦同,不会回退到 `console.error`)。
**容器 ref / 实时实例**
| 属性 | 类型 | 说明 |
| ---------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `ref` | `RefCallback` | 挂载到图表容器的 callback ref。需与自有 ref 合并时用 [`mergeRefs`](#其他导出) |
| `instance` | `ECharts \| undefined` | 响应式 —— 初始化完成后为实例,未初始化与已销毁时为 `undefined`。通过 `useEffect([instance])` 订阅实时实例并在其上挂副作用 |
**生命周期 / 更新**
| 方法 | 类型 | 说明 |
| ---------------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `setOption` | `(option: EChartsOption, opts?: SetOptionOpts) => void` | 动态更新图表配置 |
| `dispatchAction` | `(payload: Payload, opt?: boolean \| { silent?: boolean; flush?: boolean }) => void` | 派发 ECharts 动作(`highlight`、`downplay`、`showTip` 等) |
| `clear` | `() => void` | 清空当前图表内容 |
| `resize` | `(opts?: ResizeOpts) => void` | 手动触发 resize;`ResizeOpts` 支持 `width`/`height`/`animation`/`silent` |
| `appendData` | `(params: { seriesIndex: number; data: ArrayLike }) => void` | 向 series 流式追加数据。带漂移感知:会清掉去重缓存,使下次浅相等但新引用的 `option` rerender 重新调用 setOption 同步 |
**读取 / 内省**
| 方法 | 类型 | 说明 |
| ------------ | ---------------------------------- | --------------------------------------------------- |
| `getOption` | `() => EChartsOption \| undefined` | 获取当前合并后的完整配置 |
| `getWidth` | `() => number \| undefined` | 容器宽度(像素) |
| `getHeight` | `() => number \| undefined` | 容器高度(像素) |
| `getDom` | `() => HTMLElement \| undefined` | 底层 DOM 容器节点 |
| `isDisposed` | `() => boolean` | 实例是否已销毁;未初始化时返回 `true`(视作已销毁) |
**导出**
| 方法 | 类型 | 说明 |
| --------------------- | ---------------------------------------------------------- | ---------------------------------------------- |
| `getDataURL` | `(opts?) => string \| undefined` | 图片 base64 data URL(`png` / `jpeg` / `svg`) |
| `getConnectedDataURL` | `(opts?) => string \| undefined` | 同组所有图表合成的图片 |
| `renderToSVGString` | `(opts?: { useViewBox?: boolean }) => string \| undefined` | 渲染为 SVG 字符串(配合 SVG renderer 使用) |
| `getSvgDataURL` | `() => string \| undefined` | 当前图表的 SVG data URL |
**坐标转换**
| 方法 | 类型 | 说明 |
| ------------------ | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `convertToPixel` | `(finder: ChartFinder, value: ChartScaleValue \| ChartScaleValue[]) => number \| number[] \| undefined` | 逻辑坐标 → 像素坐标 |
| `convertFromPixel` | `(finder: ChartFinder, value: number \| number[]) => number \| number[] \| undefined` | 像素坐标 → 逻辑坐标 |
| `containPixel` | `(finder: ChartFinder, value: number[]) => boolean` | 像素点是否落在指定组件内(实例未初始化时返回 false) |
`ChartFinder` 为 `string | { seriesIndex?, seriesId?, …, geoIndex?, … }` —— 字符串简写或查询对象。`ChartScaleValue` 为 `number | string | Date`。
### 其他导出
```tsx
import { useLazyInit } from "react-use-echarts"; // 独立的懒加载 Hook -> { ref, isInView }
import { mergeRefs } from "react-use-echarts"; // 将多个 ref 合并为一个 callback ref
import { isBuiltinTheme, isKnownTheme, registerCustomTheme } from "react-use-echarts"; // 主题工具(不含 JSON)
import { registerBuiltinThemes } from "react-use-echarts/themes/registry"; // 内置主题 JSON(~20KB)
import { registerEchartsFull } from "react-use-echarts/preset-full"; // 一行注册全套(参见「注册 ECharts 模块」)
// 所有导出类型:UseEchartsOptions, UseEchartsReturn, UseLazyInitReturn,
// EChartProps, EChartHandle, EChartsEvents, EChartsEventConfig, EChartsEventHandler,
// EChartsEventPayloadMap, EChartsInitOpts, BuiltinTheme, LoadingOption,
// ChartFinder, ChartScaleValue, Payload。
// EChartsOption、SetOptionOpts、ResizeOpts 现在也从此处转出(源自 "echarts" 包),
// 可与上面的类型一起从 react-use-echarts 统一导入,无需再单独 import "echarts"。
```
`mergeRefs` 返回一个 callback ref,将节点分发到每个传入的 ref —— 支持 `RefObject`、旧式 callback ref、以及带 cleanup 的 React 19 callback ref —— 并对每次调用做 try/catch 隔离,第三方 ref 抛错不会拖垮图表。需要同时拿到 Hook 提供的 ref 和你自己的 ref 时使用:
```tsx
const myRef = useRef(null);
const { ref } = useEcharts({ option });
return ;
```
## 从 `echarts-for-react` 迁移
绝大多数 prop 是 1:1 对应,少数被并入现有选项。速查表:
| `echarts-for-react` | `react-use-echarts` | 说明 |
| ------------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `option` | `option` | 一致 |
| `theme` | `theme` | 一致;内置主题需先调用 `registerBuiltinThemes()`(见[主题](#主题)) |
| `notMerge` / `lazyUpdate` | `setOptionOpts: { notMerge, lazyUpdate }` | 合并为单个对象传给 `setOption` |
| `showLoading` | `showLoading` | 一致 |
| `loadingOption` | `loadingOption` | 一致 |
| `onEvents` | `onEvents` | 形态一致;也可写 `{ handler, query?, context? }` 进行 query/context 绑定 |
| `onChartReady` | 订阅响应式 `instance` | `useEffect(() => { if (instance) onReady(instance); }, [instance])`——返回的 `instance` 初始化前为 `undefined`,init/dispose 完成时会触发 re-render |
| `opts.renderer` | `renderer: 'canvas' \| 'svg'` | 提升为顶层字段 |
| `opts`(其他字段) | `initOpts` | 形态一致(`devicePixelRatio`、`locale`、`width`、`height`、`useDirtyRect` 等) |
| `style` | `style` | `` 默认 `{ width: '100%', height: '100%' }`,父容器仍需显式高度 |
| `className` | `className` | 一致 |
| `lazyUpdate`(顶层) | `setOptionOpts: { lazyUpdate: true }` | 见 `notMerge` 行 |
| `shouldSetOption` | 在父组件中自行控制 `option` | 顶层键自动经 `shallowEqual` 去重;如需自定义判断(深比较、节流、按应用状态门控),请在父组件中 memoize 或跳过 `option` prop |
| `autoResize`(4.x) | `autoResize` | 默认值同为 `true`;底层使用 ResizeObserver + RAF |
| _无_ | `lazyInit` | 新增:容器进入视口时再初始化 |
| _无_ | `group` | 新增:通过组 ID 实现图表联动 |
| _无_ | `onError` | 新增:将图表操作错误路由到回调(`init`、`setOption`、事件、loading、resize、group 联动和命令式调用) |
并排示例:
```tsx
// echarts-for-react
instanceRef.current = instance}
/>
// react-use-echarts
// chartRef.current?.instance 替代 onChartReady
```
## 从 v2.x 迁移
v3 移除了旧的 `react-use-echarts/core` 子入口。如果你的代码已经从 `react-use-echarts` 导入,并且已经在首个图表渲染前注册 ECharts 模块,则无需改动。
如果你是从 v2.0 的全量默认入口升级,或应用仍依赖 `import "echarts"` 的副作用注册,请在应用入口**加一次注册调用**:
```ts
// 应用入口(如 main.tsx, index.tsx)
import { registerEchartsFull } from "react-use-echarts/preset-full";
registerEchartsFull();
```
该调用与 v2.0 的自动 ECharts 注册等价,同样的 ~290KB-gzip 全套体验。生产构建若只渲染少数图表类型,请改用 `echarts.use([...])` 按需注册 —— 参见 [Tree-shaking](#tree-shaking)。
请把所有残留的 `from "react-use-echarts/core"` 替换为 `from "react-use-echarts"`。
## 从 v1 迁移
v2.0 翻转了 Hook 形态:返回 callback ref + 响应式 `instance`,对齐 `floating-ui/react`、`react-aria`、`downshift`、`react-hook-form` 等社区现代约定。`` 组件对外 props 完全不变,只有直接使用 Hook 的调用方以及 `` 的类型需要迁移。
| v1 | v2 | 说明 |
| ------------------------------------------------ | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `const ref = useRef(); useEcharts(ref, options)` | `const { ref } = useEcharts(options)` | Hook 自己持有 callback ref,挂到你的容器即可 |
| 返回对象上的 `getInstance()` 方法 | 同一返回对象上的 `instance` 字段 | 响应式 —— init/dispose 完成时触发 re-render,可用 `useEffect([instance])` 订阅 |
| `useLazyInit(ref, options)` 返回 `boolean` | `useLazyInit(options)` 返回 `{ ref, isInView }` | 同样改为 callback ref 形态 |
| `useRef(null)` 配 `` | `useRef(null)` 配 `` | `EChartHandle = Omit` —— 容器 ref 改由 `` 内部自管,不再暴露给外部,杜绝通过 handle 重定向 DOM 节点 |
| 手写合并多个 ref | `mergeRefs(chartRef, myRef)` | 新增公开工具(见[其他导出](#其他导出)) |
| `engines.node >=20` | `engines.node >=22` | 仅影响工具链;发布产物不变 |
并排 Hook 示例:
```tsx
// v1
const chartRef = useRef(null);
const { setOption, getInstance } = useEcharts(chartRef, { option });
useEffect(() => {
getInstance()?.on("finished", handler);
}, []);
return ;
// v2
const { ref, instance, setOption } = useEcharts({ option });
useEffect(() => {
if (!instance) return;
instance.on("finished", handler);
return () => instance.off("finished", handler);
}, [instance]);
return ;
```
## 贡献
我们欢迎所有贡献。请先阅读[贡献指南](CONTRIBUTING.md)。
## 更新日志
每个版本的详细变更请查看[发布说明](https://github.com/chensid/react-use-echarts/releases)。
## 许可证
[MIT](./LICENSE.txt) © [Ethan](https://github.com/chensid)