告警 Detected multiple renderers concurrently rendering the same context provider

使用 Arco Design 点击按钮弹框或者弹出Message提示框出现 Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported. 的警告,分析原因通常是因为在同一应用中存在多个 React 渲染器(React Renderer)并发渲染同一个 Context Provider。例如

  1. 多个 React 根节点 (React Root) 使用了相同的 Context Provider。
  2. 在测试环境或某些特殊场景下,同一个 Context 被多个独立的 React 实例渲染。
  3. 混合使用不同的 React 版本或渲染方式(如 ReactDOM 和 React Native)。

Arco Design 的某些组件(例如 Modal、Notification、Message 等)依赖全局 Context(如 ConfigProvider),当这些 Context 被多个渲染器同时操作时,就会触发此警告。


解决方法

1. 确保只有一个 React Root

检查你的应用是否创建了多个 React Root(通过 ReactDOM.rendercreateRoot)。如果有多个根节点,确保它们共享同一个 Context Provider。尤其是在使用了组件联邦的架构下,很容易出现此问题。

jsx 复制代码
// 不推荐:多个独立的 Root
ReactDOM.render(<App />, document.getElementById('root1'));
ReactDOM.render(<App />, document.getElementById('root2'));

// 推荐:只有一个 Root
ReactDOM.render(
  <ConfigProvider>
    <App />
  </ConfigProvider>,
  document.getElementById('root')
);

如果你使用 React 18 的 createRoot

jsx 复制代码
import { createRoot } from 'react-dom/client';
import { ConfigProvider } from '@arco-design/web-react';

const root = createRoot(document.getElementById('root'));
root.render(
  <ConfigProvider>
    <App />
  </ConfigProvider>
);

2. 检查 Arco 的全局组件使用方式

Arco Design 的 Modal、Notification 等组件会通过 Context 与全局状态交互。如果你手动调用这些组件的静态方法(例如 Modal.confirm),确保它们运行在同一个 React Context 树中。

错误示例:

jsx 复制代码
import { Modal } from '@arco-design/web-react';

// 在 React 树之外直接调用
Modal.confirm({
  title: '提示',
  content: '这是一个模态框',
});

正确示例: 确保 Modal 被包裹在 ConfigProvider 中:如果全局入口已经加了ConfigProvicer了还出现此警告,可以尝试在子组件继续包裹,如下

jsx 复制代码
import { ConfigProvider, Modal } from '@arco-design/web-react';

function App() {
  const showModal = () => {
    Modal.confirm({
      title: '提示',
      content: '这是一个模态框',
    });
  };

  return (
    <ConfigProvider>
      <button onClick={showModal}>打开 Modal</button>
    </ConfigProvider>
  );
}

3. 避免在测试环境中重复渲染 Context

在 Jest 或其他测试框架中,如果你在多个测试用例中重复渲染包含 ConfigProvider 的组件,可能会触发此警告。解决方法是确保每个测试用例独立清理渲染结果。

jsx 复制代码
import { render, screen } from '@testing-library/react';
import { ConfigProvider } from '@arco-design/web-react';

describe('MyComponent', () => {
  afterEach(() => {
    // 清理渲染
    document.body.innerHTML = '';
  });

  it('renders correctly', () => {
    render(
      <ConfigProvider>
        <MyComponent />
      </ConfigProvider>
    );
    expect(screen.getByText('test')).toBeInTheDocument();
  });
});

或者使用 @testing-library/reactcleanup 功能:

jsx 复制代码
import { render, screen, cleanup } from '@testing-library/react';
import { ConfigProvider } from '@arco-design/web-react';

afterEach(cleanup);

it('renders correctly', () => {
  render(
    <ConfigProvider>
      <MyComponent />
    </ConfigProvider>
  );
  expect(screen.getByText('test')).toBeInTheDocument();
});

4. 检查是否有第三方库导致的多重渲染

某些第三方库可能在独立的 React 实例中渲染组件,并与 Arco Design 的 Context 发生冲突。检查你的依赖中是否有类似情况,并尝试将这些库的渲染合并到主 React 树中。


排查步骤

  1. 定位问题来源 :在警告信息中查看完整的 Error Component Stack,找到触发警告的具体组件。
  2. 检查 Context 使用 :确认是否有多个 ConfigProvider 实例或独立渲染的 Arco 组件。
  3. 调试渲染树:使用 React Developer Tools 检查是否有多个独立的 React 树。
  4. 简化代码:逐步移除部分代码,定位触发警告的最小复现案例。

示例:完整修复后的代码

以下是一个典型的列表 + Modal 的实现:

jsx 复制代码
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
import { ConfigProvider, Modal, Form, Input, Button, Table } from '@arco-design/web-react';

const App = () => {
  const [dataSource, setDataSource] = useState([]);
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [editingItem, setEditingItem] = useState(null);
  const [form] = Form.useForm();

  const columns = [
    { title: '名称', dataIndex: 'name' },
    {
      title: '操作',
      render: (_, record) => (
        <Button onClick={() => {
          setEditingItem(record);
          form.setFieldsValue(record);
          setIsModalVisible(true);
        }}>编辑</Button>
      ),
    },
  ];

  const handleSubmit = (values) => {
    if (editingItem) {
      setDataSource(dataSource.map(item => 
        item.id === editingItem.id ? { ...item, ...values } : item
      ));
    } else {
      setDataSource([...dataSource, { id: Date.now(), ...values }]);
    }
    setIsModalVisible(false);
    form.resetFields();
    setEditingItem(null);
  };

  return (
    <ConfigProvider>
      <Button onClick={() => setIsModalVisible(true)} style={{ marginBottom: 16 }}>
        新增
      </Button>
      <Table dataSource={dataSource} columns={columns} rowKey="id" />
      <Modal
        title={editingItem ? '编辑' : '新增'}
        visible={isModalVisible}
        onCancel={() => {
          setIsModalVisible(false);
          form.resetFields();
          setEditingItem(null);
        }}
        footer={null}
      >
        <Form form={form} onFinish={handleSubmit} layout="vertical">
          <Form.Item name="name" label="名称" rules={[{ required: true }]}>
            <Input />
          </Form.Item>
          <Form.Item>
            <Button type="primary" htmlType="submit">
              提交
            </Button>
          </Form.Item>
        </Form>
      </Modal>
    </ConfigProvider>
  );
};

const root = createRoot(document.getElementById('root'));
root.render(<App />);

以上全文。

相关推荐
老黑5 小时前
开源工具 AIDA:给 AI 辅助开发加一个数据采集层,让 AI 从错误中自动学习(Glama 3A 认证)
前端·react.js·ai·nodejs·cursor·vibe coding·claude code
Highcharts.js9 小时前
React 开发者的图表库生态:Highcharts React
前端·react.js·前端框架
钛态10 小时前
Flutter 三方库 react 泛前端核心范式框架鸿蒙原生层生态级双向超能适配:跨时空重塑响应式单向数据流拓扑与高度精密生命周期树引擎解耦视图渲染控制中枢(适配鸿蒙 HarmonyOS ohos)
前端·flutter·react.js
米饭同学i11 小时前
基于腾讯云COS的小程序素材上传功能实现
前端·javascript·react.js
光影少年11 小时前
如何开发一个CLI工具?
javascript·测试工具·前端框架·node.js
哈__11 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-fingerprint-scanner
javascript·react native·react.js
北鸟南游12 小时前
使用AI智能体的MCP和SKILL
人工智能·程序员·前端框架
装不满的克莱因瓶12 小时前
React Native vs Flutter:一次深入到底的性能对比分析(含原理 + 实战)
javascript·flutter·react native·react.js·app·移动端
羊小猪~~13 小时前
【QT】-- QMainWindow简介
开发语言·数据库·c++·后端·qt·前端框架·求职招聘
qq_3680196615 小时前
用 react 的react-syntax-highlighter 实现语法高亮、行号与多行错误行高亮
前端·react.js·前端框架