I practice react
I met this error : Uncaught ReferenceError: ReactDOM is not defined
when type ReactDOM.unmountComponentAtNode(document.body) on chrome console
Please help me check the problem
I try the code on JSbin and works well,so I think it's webpack problem,but I have no idea .
And I notice there are many way write React.render part when I google ,what's the difference?? which one is correct??
React.render(<App name='Vipul' />,document.body);
ReactDOM.render(<App name='Vipul' />,document.body);
React.renderComponents(<App name='Vipul' />,document.body);
Here is my code:
main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
console.log('Start')
var App = React.createClass({
render: function(){
console.log('render');
return <h1 onClick={this.toggleState}>Hello</h1>
},
componentWillUnmount: function(){
//在console執行 ReactDOM.unmountComponentAtNode(document.body)
console.log('componentWillUnmount');
},
toggleState: function(){
this.setState({status: !this.state.status})
}
});
ReactDOM.render(<App name='Vipul' />,document.body);
webpack.config.js
var WebpackNotifierPlugin = require('webpack-notifier');
module.exports = {
entry: "./src/main.js",
output: {
filename: "./dist/bundle.js"
// filename: "./public/dist/bundle.js"
},
plugins: [
new WebpackNotifierPlugin()
],
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: "babel-loader",
query: {
presets: ['es2015', 'react']
}
}
]
},devtool: 'source-map'
};
ReactDOM available since 0.14.0, so
ReactDOM.render(<App name='Vipul' />,document.body);
should be fine. If you are using lower version of React then React.render
Secondly it is recommended not to render on document.body, rather create a div inside the body and render there.
I met this error : Uncaught ReferenceError: ReactDOM is not defined
when type ReactDOM.unmountComponentAtNode(document.body) on chrome console
when you use Webpack the React and ReactDOM will not be available globally. So, this code will only work inside the file/module where you have imported React & ReactDOM.
There is only one way to render React component in browser and it's this one:
ReactDOM.render(<App />, target);
All other are deprecated - renderComponent is renamed to render and moved from react package to react-dom package.
Also, do you need to call unmountComponentAtNode in your componentWillUnmount lifecycle method? In your particular case it does not make sense. React will unmount component for you - for free.
componentWillUnmount usually serves for clearing timeouts/intervals and/or canceling async operations (Promises, closing connections, ...);
Removing that call won't harm you, try it out.
Related
I am trying to dynamically import react component library from API. The js file is fetched succesfully. The babel transpilation has happened successfully too. If I dynamically import the Dummy.js file from localhost like import Dummy from './components/js/Dummy.js', it works. However API import fails with below error. The same error occurs with react lazy too. I basically want to dynamically load the lib and publish events to it. I am newbie to react and front-end development. Please excuse if this is too silly!.
Error resolving module specifier: react
My App.js
import React, { lazy, Suspense } from 'react';
import './App.css';
import ErrorBoundary from './ErrorBoundary';
class App extends React.Component {
render(){
const loader = () => import( /*webpackIgnore: true*/ `https://example.com/Dummy.js`);
const Dummy = ReactDynamicImport({ loader });
const LoadingMessage = () => (
"I'm loading..."
)
return (
<div className="App">
<h1>Simplewidget</h1>
<div id="simplewidget">
<ErrorBoundary>
<Suspense fallback={LoadingMessage}>
<Dummy />
</Suspense>
</ErrorBoundary>
</div>
</div>
);
}
}
export default App;
rollup.config.js, After multiple attempts I arrived at below configuration https://github.com/jaebradley/example-rollup-react-component-npm-package/blob/master/rollup.config.js
// node-resolve will resolve all the node dependencies
import resolve from '#rollup/plugin-node-resolve';
import babel from 'rollup-plugin-babel';
import commonjs from '#rollup/plugin-commonjs';
import filesize from 'rollup-plugin-filesize';
import localResolve from 'rollup-plugin-local-resolve';
export default {
input: 'src/components/js/Dummy.js',
output: {
file: 'dist/Dummy.js',
format: 'es',
globals: {
react: 'React',
'react-dom': 'ReactDOM'
}
},
// All the used libs needs to be here
external: [
'react',
'react-dom'
],
plugins: [
babel({
exclude: 'node_modules/**',
}),
localResolve(),
resolve({
browser: true,
}),
commonjs(),
filesize()
]
}
Dummy.js. I verified in dist/dummy.js that babel transpilation happened correctly. I uploaded the transpiled version to my static hosting site.
import React from "react";
import ReactDOM from "react-dom";
class Dummy extends React.Component {
render() {
return (
<h1>Hello</h1>
);
}
}
export default Dummy;
I have different targets to build, start up my server, create rollup bundle, etc in same app. So, I am pretty confident my rollup doesn't interfere with running the app.
The rollup bundling configuration isn't correct. I was trying to create an es output with commonjs plugin while actually I required an esm module. The error on 'react' is because it is unresolved. Had to make it to use window.React while doing rollup bundle. Also, the App.js should be rolled up as esm bundle to make it dynamically import Dummy.js. In the HTML where app.js's bundle is included, I had to include react and react js umd scripts.
export default {
input: "./src/components/js/Dummy.js",
output: {
file: './dist/Dummy.js',
format: 'esm'
},
plugins: [
babel({
exclude: "node_modules/**"
}),
resolve(),
externalGlobals({
"react": "window.React",
"react-dom": "window.ReactDOM",
})
]
};
I have made a browser extension which injects an iframe into the DOM that has some html in it. I have been trying to render a React component into the iframe, but it won't render and I receive the following error Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
I've tried rendering to both the iframe and even straight to the DOM via content scripts, but I still keep getting the same problem. I know the component's render function is being called, because I placed a console.log in it and it displays the message; I have also debugged it and the breakpoints stop in the render function. In addition I added the lifecycle methods componentWillUpdate and componentDidUpdate and they are not even called.
//Index.jsx
import React from "react";
import ReactDOM from "react-dom";
class Index extends React.Component{
constructor(props){
super(props);
}
componentWillUpdate(){
console.log('componentWillUpdate');
}
componentDidUpdate(){
console.log('componentDidUpdate');
}
render() {
console.log('render');
return <div>Hello!</div>;
}
}
ReactDOM.render(<Index/>, document.getElementById("g-root"))
// Including this code to show how I was adding the react component to the DOM if it is loaded immediately via manifest.json
// const app = document.createElement('div');
// app.id = "g-root";
// document.body.appendChild(app);
// ReactDOM.render(<Index />, app);
//webpack.config
const path = require('path');
module.exports = (env, args) => {
return {
mode,
devtool,
entry: {
react: path.join(__dirname, './Index.jsx')
},
module: {
rules: [{
test: /\.jsx$/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react', 'es2015']
}
}
}]
},
output: {
path: path.join(__dirname, './'),
filename: 'react.bundle.js'
}
}
};
<!--This gets loaded into the iframe-->
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="g-root"></div>
<script src="react/react.bundle.js"></script>
</body>
</html>
//manifest.json *included just to show that it has the same issue on page load.
{
"content_scripts":
[{
"js":["react/react.bundle.js"],
"run_at": "document_end",
"matches": ["<all_urls>"]
}]
}
It should be noted that injecting the iframe, and the extension as a whole, worked fine until I started trying to add React to the project.
Turns out it was an issue with an internal library having to do with rendering web components with my React components.
I'm trying to add Storybook to an existing React app but getting errors with imported svg files. The svg is imported and used like:
import Border from './images/border.inline.svg'
...
<Border className="card__border" />
This works when the app is run and built, but I get an error in Storybook. How come?
Failed to execute 'createElement' on 'Document': The tag name provided ('static/media/border.inline.258eb86a.svg') is not a valid name.
Error: Failed to execute 'createElement' on 'Document': The tag name provided ('static/media/border.inline.258eb86a.svg') is not a valid name.
The default webpack.config.js has:
...
{
test: /\.inline.svg$/,
loader: 'svg-react-loader'
},
...
Also, the existing code uses webpack 3, and I'm using Storybook V4.
This is happening because Storybook's default webpack config has its own svg config:
{
test: /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/,
loader: 'file-loader',
query: { name: 'static/media/[name].[hash:8].[ext]' }
},
I'm pretty sure this is the cause, because you can see the path outlined in error message: query: { name: 'static/media/[name].[hash:8].[ext]' } -> static/media/border.inline.258eb86a.svg
The solution can be to find the existing loader & change / or add an exclude rule to it. Here's an example of a custom .storybook/webpack.config.js:
// storybook 4
module.exports = (_, _, config) => {
// storybook 5
module.exports = ({ config }) => {
const rules = config.module.rules;
// modify storybook's file-loader rule to avoid conflicts with your inline svg
const fileLoaderRule = rules.find(rule => rule.test.test('.svg'));
fileLoaderRule.exclude = /\.inline.svg$/;
rules.push({
test: /\.inline.svg$/,
...
}],
});
return config;
};
It appears that Storybook V6 they have changed the default Webpack config. I found that the above answers didn't work for me.
They no longer have an SVG rule, therefore testing for SVG will either error or return back undefined.
There is a oneOf rule on the module.rules which contains a loader without a test as the last rule:
{
loader: '/Users/alexwiley/Work/OneUp/resources/client/node_modules/react-scripts/node_modules/file-loader/dist/cjs.js',
exclude: [Array],
options: [Object]
}
This is the culprit, you need to make sure that the file load is excluding all inline SVG file otherwise it will error.
Add the following to your .storybook/main.js file:
webpackFinal: async(config, { configType }) => {
config.module.rules.forEach((rule) => {
if (rule.oneOf) {
// Iterate over the oneOf array and look for the file loader
rule.oneOf.forEach((oneOfRule) => {
if (oneOfRule.loader && oneOfRule.loader.test('file-loader')) {
// Exclude the inline SVGs from the file loader
oneOfRule.exclude.push(/\.inline\.svg$/);
}
});
// Push your SVG loader onto the end of the oneOf array
rule.oneOf.push({
test: /\.inline\.svg$/,
exclude: /node_modules/,
loader: 'svg-react-loader', // use whatever SVG loader you need
});
}
});
return config;
}
In Storybook 6, You have to import it like this:
import { ReactComponent as Border } from './images/border.inline.svg'
Try that if it also works for your version since this question is from a year ago.
This is another way that fixed the issue for me
import Border from './images/border.inline.svg'
And then in your code
<img src={Border} alt="Border" className="w-25"/>
I got it working with
...
module.exports = {
module: {
rules: [
{
test: /\.inline.svg$/,
loader: 'svg-react-loader'
}
]
}
}
For me it was happening as I was using wrong tag name:
import React from 'react';
import RMDBLogo from '../../images/react-movie-logo.svg';
import TMDBLogo from '../../images/tmdb_logo.svg';
import { Wrapper, Content,LogoImg,TMDBLogoImg } from './Header.styles';
const Header = () => (
<Wrapper>
<Content>
<LogoImg src={RMDBLogo} alt='RMDBLogo' />
<TMDBLogo src={TMDBLogo} alt='TMDBLogo'/>
</Content>
</Wrapper>
);
export default Header;
I had imported TMDBLogoImg component while I'm using TMDBLogo tag inside Content tag.
I'm trying to convert a working ReactJS application into TypeScript, and I've had some issues getting anything to work properly.
import React from "react";
import * as ReactDOM from "react-dom";
import Application from "./Application";
console.log(React); // undefined
ReactDOM.render(
<Application/>, window.document.getElementById("application-wrapper")
);
The console throws an error at <Application />
When I import react like this, react loads:
import * as React from "react";
However, I want to use the import statement using the default export, because I import React using this import syntax in all the existing components:
import React, {Component} from "react";
export default class Whatever extends Component<Props, State> {
...
}
My tsconfig.json file contains this line allowing synthetic defaults:
"allowSyntheticDefaultImports": true
My webpack.config.js file:
let path = require("path");
let config = {
entry: "./src/main.tsx",
output: {
path: path.resolve(__dirname, "build"),
filename: "bundle.js"
},
devtool: "source-map",
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"]
},
module: {
loaders: [
{
test: /\.tsx?$/,
loader: "ts-loader",
exclude: /node_modules/
}
]
}
};
module.exports = config;
Not sure what I'm missing here....
Set "esModuleInterop": true instead.
In your typescript configuration i.e tsconfig.json "esModuleInterop": true and "allowSyntheticDefaultImports": true. this will allow you to import CommonJS modules in compliance with es6 modules spec.
Module resolution is a little complicated because Typescript does it different than Babel and Webpack. If you want to know more you can check this comment: https://github.com/Microsoft/TypeScript/issues/5565#issuecomment-155216760
Going back to your problem, allowSyntheticDefaultImports tells Typescript to allow default imports from modules with no default export but the emitted code doesn't change. Because of that, you need to move the responsibility of resolving modules to Webpack or Babel.
To achieve that set moduleResolution module to ES6es2015 in the Typescript config file.
The pipeline will look like this:
TS Code => (TypescriptCompiler) => JS Code with ES6 modules => (Webpack modules resolver) => JS Code
I'm using Webpack to bundle my ReactJS application.
helloworld.js
import React from 'react';
export default class HelloWorld extends React.Component {
render() {
return <h2>Hello {this.props.name}!</h2>;
}
}
index.js
import ReactDOM from 'react-dom';
import HelloWorld from './helloworld';
ReactDOM.render(<HelloWorld name="World" />,
document.getElementById('container'));
webpack.config.js
module.exports = {
entry: './index.js',
output: 'bundle.js',
module: {
loaders: [
{
test: /(\.js|\.jsx)/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
}
};
When I run webpack-dev-server --progress --colors I'm getting an error in the browser "React is not defined" but if I import React directly in the index.js then the error not comes. Why Webpack is not including React in the bundle if it is referenced in the helloworld.js file?
Well webpack only tries to bundle up the individual modules by reading the dependencies in it and resolving them to render a particular element. Now while bundling
ReactDOM.render(<HelloWorld name="World" />,
document.getElementById('container'));
ReactDOM tries to execute React.createElement(_Helloworld2.default, { name: 'World' }), document.getElementById('app') function which requires React as a dependency that is not present in your index.js file so it gives an error and solve the issue when you import React in your index.js file. I hope I was able to explain and my answer helps you.
You are missing import React from 'react'; statement.
You will need it every time You write some JSX in a file, because it is transformed into React.createElement(..) function calls.