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

如何在ReactJS.NET中使用React Hooks实现服务端渲染?

解决ReactJS.NET服务端渲染中使用ES6 Import和React Hooks的问题

我之前也碰到过几乎一模一样的情况——ReactJS.NET的服务端JS引擎默认不识别ES6模块语法(比如import),直接用未转译的JSX+Hooks代码肯定会报错。下面是我适配ASP.NET 4.x + .NET Framework 4.7环境整理的完整解决方案:

问题根源

你看到的SyntaxError: Unexpected identifier指向import语句,核心原因是服务端用的V8引擎只支持CommonJS的require语法,不认ES6的import/export。另外,React Hooks需要确保服务端与客户端的React版本一致,且代码经过正确转译才能被两边识别。

步骤1:用Webpack+Babel转译代码

必须把JSX和ES6+代码转译成服务端能识别的CommonJS格式,同时要把React、ReactDOM标记为外部依赖,避免重复打包。

1.1 安装必要依赖

在项目根目录运行npm命令:

npm install react react-dom @babel/core @babel/preset-env @babel/preset-react webpack webpack-cli babel-loader --save-dev

1.2 创建Babel配置文件(.babelrc)

{
  "presets": [
    ["@babel/preset-env", { "targets": { "node": "current" } }],
    "@babel/preset-react"
  ]
}

preset-env针对当前Node版本(和V8引擎兼容),preset-react专门处理JSX和React Hooks语法。

1.3 创建Webpack配置文件(webpack.config.js)

const path = require('path');

module.exports = {
  entry: './Scripts/Components/Customer/ChildrenForm.jsx',
  output: {
    path: path.resolve(__dirname, './Scripts/Bundles'),
    filename: 'ChildrenForm.bundle.js',
    libraryTarget: 'commonjs2' // 输出CommonJS格式,让服务端能require加载
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      }
    ]
  },
  externals: {
    'react': 'commonjs react',
    'react-dom': 'commonjs react-dom'
  },
  resolve: {
    extensions: ['.js', '.jsx']
  }
};
  • libraryTarget: 'commonjs2'是关键,确保打包后的代码能被服务端引擎识别
  • externals把React和ReactDOM标记为外部依赖,让服务端直接引用项目里的React脚本,不用打包进去

1.4 执行打包

在命令行运行:

npx webpack --mode production

打包完成后,会在Scripts/Bundles目录下生成ChildrenForm.bundle.js

步骤2:调整ReactConfig.cs配置

修改配置,引用转译后的bundle,同时要确保服务端先加载React核心库:

namespace Nop.Web {
    public static class ReactConfig {
        public static void Configure() {
            ReactSiteConfiguration.Configuration
                // 先加载React和ReactDOM的UMD版本,让服务端能全局访问React
                .AddScript("~/Scripts/react.development.js")
                .AddScript("~/Scripts/react-dom.development.js")
                // 引用转译后的bundle,替换原来的原始JSX文件
                .AddScript("~/Scripts/Bundles/ChildrenForm.bundle.js");
            
            JsEngineSwitcher.Current.DefaultEngineName = V8JsEngine.EngineName;
            JsEngineSwitcher.Current.EngineFactories.AddV8();
        }
    }
}

提示:你可以通过npm安装React后,把node_modules/react/umd下的脚本复制到项目的Scripts目录,服务端渲染建议用本地文件而非CDN,避免网络问题。

步骤3:组件代码的小调整(确保Hooks服务端兼容)

你的Hooks写法本身没问题,但要注意服务端渲染时useEffect不会执行,所以初始状态必须直接从props获取,避免客户端和服务端渲染的内容不一致:

import React, { useState, useEffect } from 'react';

const ChildrenForm = (props) => {
    // 直接用props初始化state,服务端渲染时会生成正确的初始HTML
    const [familyTiesId, setFamilyTiesId] = useState(props.familyTiesId);

    // useEffect只在客户端执行,服务端会自动忽略
    useEffect(() => {
        // 这里放客户端专属逻辑,比如请求数据、绑定事件等
    }, []);

    return (
        <div>
            <p>Family Ties ID: {familyTiesId}</p>
            {/* 其他组件内容 */}
        </div>
    );
};

// 必须导出组件,供服务端引用
export default ChildrenForm;

步骤4:验证视图代码

你的视图代码可以保持不变,但要注意serverOnly:true只是测试用,正式环境需要开启客户端 hydration(让客户端接管服务端渲染的HTML):

@Html.React("ChildrenForm", new { familyTiesId = Model.FamilyTiesId }, serverOnly:true )

开启客户端hydration的话,需要在页面底部添加@Html.ReactInitJavaScript(),同时确保客户端也加载了React和bundle文件。

常见问题排查

  • 如果报错"React is not defined":检查React脚本是否在bundle之前加载,且文件路径正确
  • 如果Hooks报错:确保React版本是16.8+,且服务端和客户端的React版本完全一致
  • 打包后bundle无法被服务端识别:检查Webpack的libraryTarget是否设为commonjs2,组件是否有export default

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:17:18