首页 > 解决方案 > 错误 ReferenceError: React 未定义 | 在 Angular 中使用 React 组件

问题描述

所以基本上我想将一个 React 组件(一个通知组件)渲染到我的 Angular 项目中。我建立Notification.tsx

import * as React from 'react';
import { FunctionComponent, useEffect, useRef, useState } from 'react';
import { IconButton, Badge, Menu, List, ListItem, ListItemIcon, ListItemText, ListItemSecondaryAction, Avatar } from '@material-ui/core';
import { Notifications, Delete, Event, HourglassEmpty, Alarm } from '@material-ui/icons';
import { makeStyles } from '@material-ui/core/styles';
import { grey } from '@material-ui/core/colors';

export interface NotificationProps { }

export const NotificationComponent: FunctionComponent<NotificationProps> = (props: NotificationProps) => {
    return <div className={"row"}>
        <IconButton disableRipple={true} aria-label="notification" className="py-3 my-auto"
            onClick={handleNotificationMenuClick} aria-controls="notification-drop-down-menu"
            aria-haspopup="true">
            <Badge badgeContent={4} max={99} color="secondary">
                <Notifications />
            </Badge>
        </IconButton>
    </div>
};

包装器组件NotificationWrapper.tsx

import { AfterViewInit, Component, ElementRef, OnChanges, OnDestroy, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { NotificationComponent } from './Notification';
import * as React from 'react';
import * as ReactDOM from 'react-dom';

const containerElementName = 'notificationComponentTemplate';

@Component({
    selector: 'react-notification-component',
    template: `<span #${containerElementName}></span>`,
    encapsulation: ViewEncapsulation.None,
})
export class NotificationWrapper implements OnChanges, OnDestroy, AfterViewInit {
    @ViewChild(containerElementName, { static: false }) containerRef: ElementRef;

    constructor() { }

    ngOnChanges(changes: SimpleChanges): void {
        this.render();
    }

    ngAfterViewInit() {
        this.render();
    }

    ngOnDestroy() {
        ReactDOM.unmountComponentAtNode(this.containerRef.nativeElement);
    }

    private render() {
        ReactDOM.render(<div className={'notification-wrapper'}>
            <NotificationComponent />
        </div>, this.containerRef.nativeElement);
    }
}

将此包装器添加app.module.ts@NgModule

import { NotificationWrapper } from "../react-components/notification/NotificationWrapper";

@NgModule({
  declarations: [
    NotificationWrapper,
  ],
})

使用通知包装器选择器如下:

        <div class="col-sm-6">
          <react-notification-component></react-notification-component>
        </div>

在本地服务时一切正常,当我在这个网站上遇到其他类似问题时:我已经添加"jsx": "react"tsconfig.json

  plugins: [
    new webpack.ProvidePlugin({
      "React": "react",
    })
  ]

  externals: {
    'react': 'React'
  },

webpack.config.js. 这是整个文件以供参考。

// Work around for https://github.com/angular/angular-cli/issues/7200

const path = require('path');
const webpack = require('webpack');
// change the regex to include the packages you want to exclude
const regex = /firebase\/(app|firestore)/;

module.exports = {
  mode: 'production',
  entry: {
    // This is our Express server for Dynamic universal
    server: './server.ts'
  },
  externals: {
    './dist/server/main': 'require("./server/main")',
    'react': 'React'
  },
  target: 'node',
  node: {
    __dirname: false,
    __filename: false,
  },
  resolve: { extensions: ['.ts', '.js'] },
  target: 'node',
  mode: 'none',
  // this makes sure we include node_modules and other 3rd party libraries
  externals: [/node_modules/, function (context, request, callback) {
    // exclude firebase products from being bundled, so they will be loaded using require() at runtime.
    if (regex.test(request)) {
      return callback(null, 'commonjs ' + request);
    }
    callback();
  }],
  optimization: {
    minimize: false
  },
  output: {
    // Puts the output at the root of the dist folder
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    noParse: /polyfills-.*\.js/,
    rules: [
      { test: /\.ts$/, loader: 'ts-loader' },
      {
        // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
        // Removing this will cause deprecation warnings to appear.
        test: /(\\|\/)@angular(\\|\/)core(\\|\/).+\.js$/,
        parser: { system: true },
      },
    ]
  },
  plugins: [
    new webpack.ProvidePlugin({
      "React": "react",
    }),
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?angular(\\|\/)core(.+)?/,
      path.join(__dirname, 'src'), // location of your src
      {} // a map of your routes
    ),
    new webpack.ContextReplacementPlugin(
      // fixes WARNING Critical dependency: the request of a dependency is an expression
      /(.+)?express(\\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ]
};

我的问题是,当我构建我的应用程序时,通知组件未呈现,并且我在控制台中收到此错误ERROR ReferenceError: React is not defined。有什么我错过的吗?提前致谢。

标签: javascriptreactjsangulartypescriptwebpack

解决方案


将以下内容添加到tsconfig.json

"compilerOptions": {
  "allowSyntheticDefaultImports": true,
  "jsx": "react",
}

设置aotbuildOptimizer为假angular.json

代替

import * as React from 'react';
import * as ReactDOM from 'react-dom'

import React from 'react';
import ReactDOM from 'react-dom';

推荐阅读