[PR #20161] fix(echarts): Resolve chart flickering and animation loop in Markdown #29322

Closed
opened 2026-02-21 20:45:19 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langgenius/dify/pull/20161

State: closed
Merged: Yes


Addresses the ECharts flickering issue observed during streaming output. This is achieved by:

  1. Memoizing ReactEcharts props (style, opts, onEvents) to prevent re-renders from new object references.
  2. Refining the useEffect hook for resize handling to use [language, chartState] dependencies, ensuring it only runs when necessary.
  3. Applying type assertions to echartsOpts to resolve TypeScript errors (e.g., renderer and width properties).

Summary

This pull request fixes a UI bug where ECharts visualizations within the Markdown component would continuously "blink" or re-animate during streaming output of subsequent non-ECharts content. The root cause was identified as unnecessary re-renders of the ReactEcharts component, triggered by new prop object references and overly sensitive effect dependencies.

Motivation and Context:
The flickering ECharts provided a poor user experience, especially in chat interfaces or any feature involving real-time streaming of mixed Markdown content. The constant re-animation was distracting and gave the impression of instability or continuous reloading. This change aims to stabilize the ECharts rendering, ensuring they render once and remain static unless their actual data or relevant state changes.

Fixes Implemented:

  • Stable Props for ReactEcharts: The style, opts, and onEvents props passed to the ReactEcharts component in CodeBlock.tsx are now memoized using useMemo. This prevents new object references on each parent render, thereby stopping ReactEcharts from re-rendering unnecessarily when its actual data hasn't changed.
  • Refined Resize Effect Logic: The useEffect hook responsible for handling ECharts container resizing has been updated. Its dependencies are now [language, chartState], making it less prone to re-run due to unrelated parent component updates. It now only re-evaluates when the chart language changes or its loading/success state transitions, ensuring resize logic is applied only when the chart is ready and stable.
  • Type Correction for echartsOpts: Addressed TypeScript errors for the echartsOpts object by applying as const to its renderer and width properties (or as any as a temporary measure if precise types were elusive). This ensures type compatibility with the echarts-for-react library's expected Opts type. (Self-note: If 'as any' was used, ideally this should be revisited to use the exact Opts type from the library for better type safety).

This PR aims to resolve issue

#20101

Before

https://github.com/user-attachments/assets/2870454e-b2a1-4978-9f4a-e8f630323e10

After

https://github.com/user-attachments/assets/954ae055-8583-43c1-9551-b1c600c888b3

Dependencies:
No new external dependencies are introduced by this change. The modifications are within the existing React components and TypeScript typings.

Checklist

Important

Please review the checklist below before submitting your pull request.

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. (注:UI 交互的 bug 修复,单元测试可能较难覆盖,端到端测试或手动验证更为关键)
  • I've updated the documentation accordingly.
  • [] I ran dev/reformat(backend) and cd web && npx lint-staged(frontend) to appease the lint gods
**Original Pull Request:** https://github.com/langgenius/dify/pull/20161 **State:** closed **Merged:** Yes --- Addresses the ECharts flickering issue observed during streaming output. This is achieved by: 1. Memoizing `ReactEcharts` props (`style`, `opts`, `onEvents`) to prevent re-renders from new object references. 2. Refining the `useEffect` hook for resize handling to use `[language, chartState]` dependencies, ensuring it only runs when necessary. 3. Applying type assertions to `echartsOpts` to resolve TypeScript errors (e.g., `renderer` and `width` properties). # Summary This pull request fixes a UI bug where ECharts visualizations within the Markdown component would continuously "blink" or re-animate during streaming output of subsequent non-ECharts content. The root cause was identified as unnecessary re-renders of the `ReactEcharts` component, triggered by new prop object references and overly sensitive effect dependencies. **Motivation and Context:** The flickering ECharts provided a poor user experience, especially in chat interfaces or any feature involving real-time streaming of mixed Markdown content. The constant re-animation was distracting and gave the impression of instability or continuous reloading. This change aims to stabilize the ECharts rendering, ensuring they render once and remain static unless their actual data or relevant state changes. **Fixes Implemented:** * **Stable Props for `ReactEcharts`**: The `style`, `opts`, and `onEvents` props passed to the `ReactEcharts` component in `CodeBlock.tsx` are now memoized using `useMemo`. This prevents new object references on each parent render, thereby stopping `ReactEcharts` from re-rendering unnecessarily when its actual data hasn't changed. * **Refined Resize Effect Logic**: The `useEffect` hook responsible for handling ECharts container resizing has been updated. Its dependencies are now `[language, chartState]`, making it less prone to re-run due to unrelated parent component updates. It now only re-evaluates when the chart language changes or its loading/success state transitions, ensuring resize logic is applied only when the chart is ready and stable. * **Type Correction for `echartsOpts`**: Addressed TypeScript errors for the `echartsOpts` object by applying `as const` to its `renderer` and `width` properties (or `as any` as a temporary measure if precise types were elusive). This ensures type compatibility with the `echarts-for-react` library's expected `Opts` type. *(Self-note: If 'as any' was used, ideally this should be revisited to use the exact Opts type from the library for better type safety).* This PR aims to resolve issue #20101 Before https://github.com/user-attachments/assets/2870454e-b2a1-4978-9f4a-e8f630323e10 After https://github.com/user-attachments/assets/954ae055-8583-43c1-9551-b1c600c888b3 **Dependencies:** No new external dependencies are introduced by this change. The modifications are within the existing React components and TypeScript typings. # Checklist > [!IMPORTANT] > Please review the checklist below before submitting your pull request. - [ ] This change requires a documentation update, included: [Dify Document](https://github.com/langgenius/dify-docs) - [x] I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!) - [ ] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. *(注:UI 交互的 bug 修复,单元测试可能较难覆盖,端到端测试或手动验证更为关键)* - [ ] I've updated the documentation accordingly. - [] I ran `dev/reformat`(backend) and `cd web && npx lint-staged`(frontend) to appease the lint gods
yindo added the pull-request label 2026-02-21 20:45:19 -05:00
yindo closed this issue 2026-02-21 20:45:19 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#29322