
React 18 废弃了 ReactDOM.render(),改用 createRoot() 初始化根节点;若仍使用旧 API,会导致 Hook(如 useState)调用失效并抛出“Invalid hook call”及“Cannot read properties of null”错误。
react 18 废弃了 `reactdom.render()`,改用 `createroot()` 初始化根节点;若仍使用旧 api,会导致 hook(如 `usestate`)调用失效并抛出“invalid hook call”及“cannot read properties of null”错误。
在 ASP.NET Core + React + Webpack 5 的项目中,你遇到的 Warning: Invalid hook call 和 Uncaught TypeError: Cannot read properties of null (reading 'useState') 并非代码语法错误,而是 React 18 的渲染机制不兼容导致的运行时崩溃。
根本原因在于:React 18 引入了并发渲染(Concurrent Rendering),彻底移除了 ReactDOM.render() 方法,并要求通过 react-dom/client 中的 createRoot() 创建可挂载的根容器。若继续使用已废弃的 ReactDOM.render(),React 内部无法正确初始化 Hook 系统(例如 useState 所依赖的 fiber 栈和当前渲染上下文),从而触发上述两类连锁报错。
✅ 正确做法如下:
- 更新导入路径:确保从 react-dom/client 导入 createRoot,而非仅 react-dom;
-
替换渲染逻辑:用 createRoot(container).render(
) 替代 ReactDOM.render( , container); - 保持 JSX 导入一致性:无需写 React.useState —— 只要正确配置模块解析且未发生重复 React 实例(如多版本共存),解构导入 useState 完全合法。
修改后的 index.jsx 示例:
import { useState } from "react";
import { createRoot } from "react-dom/client"; // ✅ 关键:从 client 子模块导入
function App() {
const [value, setValue] = useState(10);
return <div classname="app">{value}</div>;
}
// ✅ 使用 createRoot 替代 ReactDOM.render
const rootElement = document.getElementById("root");
if (rootElement) {
const root = createRoot(rootElement);
root.render(<app></app>);
} else {
console.error("Failed to find root element with id 'root'");
}
⚠️ 注意事项:
- 确保 react 和 react-dom 版本均为 ^18.0.0 或更高(检查 package.json);
- Webpack 配置中避免 externals 错误排除 React(如 "react": "React"),否则可能引入全局 React 17 实例,与本地安装的 React 18 冲突;
- 不要混用 ReactDOM.render() 和 createRoot();同一应用中必须统一为 React 18 模式;
- 若使用 TypeScript,请确认 @types/react 和 @types/react-dom 版本匹配 React 主版本(如 @types/react@18.x)。
? 小结:该问题本质是 React 版本迁移适配问题,而非代码缺陷。修复后,你可继续优雅地使用 import { useState } from 'react',无需回退到 React.useState 冗余写法。











