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

React18+TS调用createRoot报错TypeError: m.createRoot is not a function

问题根因

这个报错和Leaflet无关,核心原因是项目运行时实际加载的react-dom版本低于18.0.0,createRoot是React 18才在react-dom中新增的API,低版本不存在该方法,你调试时看到引入的react-dom实例m上没有createRoot就是最直接的证据。

排查&修复步骤
  • 校验实际安装的依赖版本
    执行对应包管理工具的命令,查看项目中react、react-dom的实际安装版本:
    # npm 用户
    npm ls react react-dom
    # yarn 用户
    yarn list react react-dom
    # pnpm 用户
    pnpm ls react react-dom
    
    正常要求两个包的版本均>=18.0.0,如果出现react-dom版本低于18,或者存在依赖嵌套引入了17.x版本的react-dom,就会触发该报错。
  • 对齐全项目react-dom版本
    如果是未升级react-dom,直接执行安装命令升级到18大版本即可:
    # npm 用户
    npm install react@^18 react-dom@^18
    # yarn 用户
    yarn add react@^18 react-dom@^18
    # pnpm 用户
    pnpm add react@^18 react-dom@^18
    
    如果是第三方依赖偷偷引入了低版本react-dom,通过包管理的强制版本配置统一全项目的react-dom版本:
    npm 8.3+ 版本在package.json中添加如下配置:
    {
      "overrides": {
        "react-dom": "^18.2.0"
      }
    }
    
    yarn 在package.json中添加如下配置:
    {
      "resolutions": {
        "react-dom": "^18.2.0"
      }
    }
    
    配置完成后重新执行依赖安装命令即可。
  • 检查构建配置
    如果确认所有依赖版本都符合要求仍报错,检查构建工具(webpack/vite/rollup等)的路径别名配置,是否错误将react-dom指向了本地留存的旧版本文件,修正别名指向正确的依赖路径即可。
代码优化参考

版本问题修复后,原有控件逻辑可以补充root卸载逻辑,避免内存泄漏,同时修正useEffect依赖避免重复创建控件:

import { MutableRefObject, ReactElement, useEffect } from 'react'
import L, { Map } from 'leaflet'
import { createRoot } from 'react-dom/client'

interface MapControlElementProps {
    mapRef: MutableRefObject<Map | null>
    button: ReactElement
    position: L.ControlPosition
}

export default function TestElement(props: MapControlElementProps) {
    useEffect(() => {
        const { mapRef, button, position } = props
        if (!mapRef.current) return

        let root: ReturnType<typeof createRoot> | null = null
        const MapHelp = L.Control.extend({
            onAdd: () => {
                const controlElement = L.DomUtil.create(
                    'div',
                    'leaflet-control leaflet-bar'
                )
                root = createRoot(controlElement)
                root.render(button)
                return controlElement
            },
            onRemove: () => {
                root?.unmount()
            }
        })
        const control = new MapHelp({ position })
        control.addTo(mapRef.current)
        
        return () => {
            control.remove()
        }
    }, [mapRef, button, position])

    return null
}

内容的提问来源于stack exchange,提问作者LLauk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:21:20