【问题标题】:ERROR ReferenceError: React is not defined | Using React Components in Angular错误 ReferenceError: React 未定义 |在 Angular 中使用 React 组件
【发布时间】:2021-06-07 10:26:14
【问题描述】:

所以基本上我想将一个 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 中收到此错误。有什么我错过的吗?提前致谢。

【问题讨论】:

    标签: javascript reactjs angular typescript webpack


    【解决方案1】:

    将以下内容添加到tsconfig.json

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

    angular.json 中将aotbuildOptimizer 设置为false

    替换

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

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

    【讨论】:

    • 遇到同样的问题,虽然这个解决方案对我不起作用,但我可以让它工作的唯一方法是将 angular.json 中的“优化”设置为 false。但不是我真正想做的事情:(
    • aotbuildOptimizer 设置为false
    • 我做到了,您已经说过,在您的解决方案中,在我的情况下,将 Angular 11 从 10 升级到您的解决方案
    【解决方案2】:

    我认为在最终的js中去掉React是典型的不需要的优化(React没有直接使用)

    尝试在 React 上调用方法或属性,例如 React.version

    import {
      OnChanges,
      ViewChild
    } from '@angular/core';
    import { MyComponent } from './react/MyComponent';
    import * as React from 'react';
    import * as ReactDOM from 'react-dom';
    
    const containerElementName = 'myReactComponentContainer';
    
    @Component({
      ...
    })
    export class MyComponent implements OnChanges {
    
      @ViewChild(containerElementName) containerRef: ElementRef;
      ngOnChanges(changes: SimpleChanges): void {
        this.render();
      }
    
      private render() {
        React.version;
        ReactDOM.render(<MyReactComponent />,     this.containerRef.nativeElement);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-01
      • 2023-03-31
      • 2021-02-28
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 2021-02-02
      • 2023-01-12
      相关资源
      最近更新 更多