React Component from jsx is not rendering to html - javascript

I am new to react and webpack configuration just trying with basic program.
I am not able to see any exception while running in localhost:8080 but not able to see the data in return statement of Render Component too. Please help me:
My React Component:
import React from 'react';
import ReactDOM from 'react-dom';
import SearchBar from '../search/search_bar';
export default class Index extends React.Component{
render()
{
return (<div>Hi Its me</div>);
}
}
html Page:
React Component is here:
<Index/>
<script src="bundle.js"></script>
webpack.config.js:
var path = require('path');
webpack = require('webpack');
var BUILD_DIR = path.resolve(__dirname, './src/client/public');
var APP_DIR = path.resolve(__dirname, './src/client/app');
module.exports = {
entry: APP_DIR + '/index.jsx',
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/public/'
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
},
resolve: {
extensions: ['', '.js', '.jsx'],
}
};

You can't render the component in an HTML file, so this:
<Index/>
<script src="bundle.js"></script>
is invalid. You need to render the application in your entry file index.js using the ReactDOM.render method, like this:
ReactDOM.render(
<Index />,
document.getElementById('#app'),
)
Then create that tag in your html file like this:
<div id="app"></div>
<script src="bundle.js"></script>
The principle of JSX is that it allows you to render HTML inside the JavaScript using a familiar syntax. All your components will always need to be rendered from inside your JS files.

Related

Why am I getting Uncaught ReferenceError: React is not defined?

I am setting up webpack and react in a SpringMVC webapp and I'm getting this error when hitting my /index page.
The relevant controller method is here
#RequestMapping("/index")
public ModelAndView index(final HttpServletRequest request) {
return new ModelAndView("index");
}
The template at src/main/resource/templates/index.html looks like this
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Webpack App</title>
</head>
<body>
<span>React Content Below:</span>
<div id="content"/>
</body>
<script type="text/javascript" src="http://localhost:3000/dist/app.js">
</script>
</html>
Now onto the meat. My webpack.config.js looks like this
// Generated using webpack-cli http://github.com/webpack-cli
const path = require('path');
const webpack = require("webpack");
module.exports = {
mode: 'development',
entry: './src-js/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js',
},
devServer: {
open: true,
host: 'localhost',
port:3000
},
externals: {
'react': 'React'
},
module: {
rules: [
{
test: /\.js|jsx$/,
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-env',
'#babel/preset-react',
]
}
},
{
test: /\.css$/i,
use: ['style-loader','css-loader'],
},
{
test: /\.s[ac]ss$/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/,
type: 'asset',
},
// Add your rules for custom modules here
// Learn more about loaders from https://webpack.js.org/loaders/
],
},
};
and my ./src-js/app.js looks like this.
import * as ReactDOM from "react-dom";
ReactDOM.render(<h1>Hello, world</h1>, document.getElementById('content'));
I later ammended app.js to look like this
import * as React from 'react';
import * as ReactDOM from 'react-dom'
class Component extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
return <h1>Hello, world</h1>
}
}
ReactDOM.render(<Component/>, document.getElementById('content'));
This works for now but long term I would prefer to not need to import React from this file and wrap everything in a Component.
Adding import React from 'react' to the top of app.js has no effect and neither does var React = require('react'). I'm assuming I'm just missing something in my webpack config but I can't seem to find what, anyone know why this is happening?
In the webpack documentation (https://webpack.js.org/configuration/externals/) it looks like there are no quotes before the colon:
externals: {
react: 'React'
},
A few lines below (https://webpack.js.org/configuration/externals/#object) you can find react in lowerCase:
externals: {
react: 'react'
},

How do you export react library component with hooks to use in html file?

I am getting an error when trying to export a library component to use in a window environment where we will not be using imports, and am getting an error Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. There is no duplicate version of react as it is being consumed by a simple html file.
My webpack file looks like
const config = {
mode: 'development',
externals: {
react: 'React',
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
modules: [path.resolve(__dirname), path.resolve(__dirname, 'src'), 'node_modules'],
},
module: {
rules: [
{
test: /\.(ts|js)x?$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
],
},
entry: path.resolve(__dirname, './src/components/GlobalNav/index.tsx'),
output: {
path: path.resolve(__dirname, './global-nav/dist'),
publicPath: '/',
library: 'GlobalNav',
filename: 'globalNav-blog.js',
libraryTarget: 'window',
},
};
and exporting a simple component
const GlobalNav = () => {
const [test, setTest] = React.useState(33);
return (
<div>test</div>
);
};
export default GlobalNav;
and used in a simple html file
<script
crossorigin
src="https://unpkg.com/react#16/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"
></script>
<!--......-->
<script src="/globalNav.js"></script>
<script>
(function () {
var root = document.getElementById("root");
var GlobalNav = window.GlobalNav.default();
ReactDOM.render(
GlobalNav,
root
);
})();
</script>
If I remove the use of hooks then it works. How do you export a react component with hooks as a library to be used in an environment without imports?
You are invoking the functional component as a function, not as a component.
var GlobalNav = window.GlobalNav.default();
ReactDOM.render(
GlobalNav,
root
);
Try using React.createElement.
var GlobalNav = window.GlobalNav.default;
ReactDOM.render(
React.createElement(GlobalNav),
root
);

React-hot-loader doesn't work with React-router-dom

So I've finally setup a working project with:
Electron (2.0.2)
React (16.4.0)
React-router-dom (4.2.2)
Webpack (4.11.0)
React-hot-loader (4.2.0)
And just when I started to develop some react components I noticed my project won't hot reload correctly. If I adjust something on the base url (/) it is updated correctly, but if I update something on a secondary url, say /test the webpack compiles, but I get the message Cannot GET /test.
I've tried a lot and I cannot seem to figure out what I am doing wrong. I looked into react-router-dom, since hot-reloading was an issue back in version 3.x, but they say it should be resolved now (in 4.x --> It works here..). Also i've added <base href="/"/> in my index.html so that is not it.
Can anyone tell me what I am doing wrong?
Webpack.common.js (This is merged into Webpack.dev.js)
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
resolve: {
modules: [path.resolve(__dirname), 'node_modules']
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
cacheDirectory: true,
presets: ['env', 'react'],
plugins: ['transform-runtime'],
env: {
development: {
plugins: ['react-hot-loader/babel']
},
production: {
presets: ['react-optimize']
}
}
}
}
]
}
};
Webpack.dev.js
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-source-map',
entry: {
'app': [
'babel-polyfill',
'react-hot-loader/patch',
path.join(__dirname, 'src', 'index.js')
]
},
plugins: [
new webpack.HotModuleReplacementPlugin() // Enable hot module replacement
]
});
Index.js
import React from "react";
import ReactDOM from "react-dom";
import { AppContainer } from "react-hot-loader";
import { App } from "./app";
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component/>
</AppContainer>,
document.getElementById("root")
);
};
render(App);
if (module.hot) {
module.hot.accept("./app", () => {
render(App);
});
}
App.js (my main entry point for my app, thus where I define my base routing)
import React, { Component } from 'react';
import { BrowserRouter, Route, NavLink } from 'react-router-dom';
import { Test } from './components/test';
import { Test2 } from './components/test2';
export class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<NavLink to="/">Home</NavLink>
<NavLink to="/test">Test</NavLink>
<div>
<Route exact path="/" component={Test}/>
<Route path="/test" component={Test2}/>
</div>
</div>
</BrowserRouter>
);
}
}
And the components 'test' and 'test2' are just plain simple react components with a 'hello world' text.
Anyone who sees anything that I am missing or doing wrong?
Thanks to this tutorial I found a way to adapt my project and get hot loading to work. It even made my code a bit cleaner and my build scripts simpeler.
Webpack.common.js
The first thing I needed to change was the babel-loader. I stole it from some tutorial, and it worked, but I did not know exactly what it did so I got rid of that code. I've also made the compilation of my code faster through the webpack.DllReferencePlugin.
Here is the updated webpack.common.js:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
entry: {
app: [
'babel-polyfill',
'./src/index.js',
],
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
plugins: ['react-hot-loader/babel'],
cacheDirectory: true,
presets: ['env', 'react'],
},
}
],
},
plugins: [
new webpack.DllReferencePlugin({
context: path.join(__dirname),
manifest: require('../dist/vendor-manifest.json'),
}),
new HtmlWebpackPlugin({
title: '<my-app-name>',
filename: 'index.html',
template: './public/index.html',
}),
new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, '../dist/*.dll.js'),
includeSourcemap: false // add this parameter
})
],
};
The AddAssetHtmlPlugin is required since the index.html is dynamically created (by the HtmlWebpackPlugin) for the dev server and you cannot hardcode the correct bundle import for the vendor.dll and the app.bundle (more here).
webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack');
const path = require('path');
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-source-map',
devServer: {
hot: true,
contentBase: path.resolve(__dirname, 'dist'),
historyApiFallback: true // Allow refreshing of the page
},
plugins: [
new webpack.HotModuleReplacementPlugin(), // Enable hot reloading
]
});
What did I change:
I moved the entry point up to webpack.common.
I Removed the 'react-hot-loader/patch' from the entry
(optional) I've added some config options for the webpack-dev-server.
Index.js
This is the file that caused the hot-reload to fail. Especially the if(module.hot) part caused it to fail. So I've changed it to the following:
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import { App } from './app';
const render = () => {
ReactDOM.render(
<AppContainer>
<App/>
</AppContainer>,
document.getElementById('app'),
);
};
render(App);
if (module.hot) {
module.hot.accept('./app', () => {
const NextApp = require('./app').default; // Get the updated code
render(NextApp);
});
}
The reason it works now is because now I fetch the new app and replace the old one, thus telling the hot-loader there has been a change. I could also just use module.hot.accept(), but that would make the react-hot-loader useless (you make use of the webpack hot-reloader) and this way I would also lose the state within my components every time I updated some code.
So there you go. I hope this will help anyone (other then myself).

React doesn't append class from className

I have a problem with React and don't know why, but React doesn't appent the attribute class in rendered HTML code. I import css file in body, import styles in react script, write className attribute, etc..
The result on page will be block without class – <div>test</div>
In App.js
import React, {Component} from 'react';
import styles from '../assets/main.css';
export default class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div className={styles.test}>test</div>
</div>
);
}
}
In main.css
.test {
color: red;
}
Webpack config
const HTMLWebpackPlugin = require('html-webpack-plugin');
const HTMLWebpackPluginConfig = new HTMLWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html',
inject: 'body'
});
const webpack = require('webpack');
module.exports = {
entry: [
'react-hot-loader/patch',
__dirname + '/app/index.js'
],
devServer: {
hot: true
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
}
]
},
output: {
filename: 'transformed.js',
path: __dirname + '/build'
},
plugins: [
HTMLWebpackPluginConfig,
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
resolve: {
extensions: ['.js', '.jsx', '.css']
}
};
Importing your CSS stylesheet just causes Webpack to bundle it along with the rest of your JavaScript. You can't add styles.test as an attribute, that won't do anything. You need to specify the className as a string, just like you would for an HTML element.
render() {
return (
<div>
<div className="test" >test</div>
</div>
);
}
I think you should try importing your main.css file in your entry file i.e app/index.js. You don't need to add {styles.test} in className.
import './assets/main.css';
When the webpack bundle will run it will take all your css.
You just need to give same className like :
<div>
<div className='test'>test</div>
</div>
Also, make sure you have installed all loaders like file-loader, css-loader, url-loader, style-loader and included them in your webpack.config file.

React do not render new components, new webpack setup

Today I was setting up my first Webpack Bebel React project and I got some strange case here.I don't know why, but every single Component that I make is not recognized by React. I can see it directly in the inspector, and It seems like it's not getting compiled. All standard HTML elements are getting rendered. Even console.log inside of constructor function of a component that I have created is not called. I run Hot mode with webpack -p
Here is my Webpack config:
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const webpack = require('webpack')
const path = require('path')
const isProduction = process.env.NODE_ENV === 'production'
const cssDeveloperLoaders = ['style-loader', 'css-loader', 'sass-loader']
const cssProduction = ExtractTextPlugin.extract({
fallback: 'style-loader',
loader: ['css-loader', 'sass-loader'],
publicPath: '/dist'
})
const cssConfig = isProduction ? cssProduction : cssDeveloperLoaders
module.exports = {
entry: {
app: './src/app.jsx'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
module: {
rules: [
{
test: /\.scss$/,
use: cssConfig
},
{
test: /\.jsx$/,
exclude: path.resolve(__dirname + '/node_modules/'),
use: 'babel-loader',
query: {
presents: ['es2015','react']
}
}
]
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
hot: true,
open: true,
openPage: '' //Fix to webpack version 3.0.0 after removing redirection to /undefined
},
plugins: [
new ExtractTextPlugin({
filename: 'app.css',
disable: !isProduction, //So if production is running it will generate file otherwise not
allChunks: true
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin()
]
}
My .bablerc
{
"presets": [
"es2015",
"react"
]
}
App.jsx:
import './app.scss'
import React from 'react';
import { render } from 'react-dom';
import engine from './engine.jsx'
render(
<engine/>,
document.getElementById('root')
);
engine.jsx
import React from 'react';
class engine extends React.Component{
constructor(){
super();
console.log('Component has been constructed ')
}
render(){
return(
<div>xD</div>
)
}
}
export default engine;
The picture of React Chrome extension.
Please notice, console.log is not been called.
My html is empty, I see only engine element (Not compiled.)
Any suggestions about this problem?
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="root"></div>
<script src="app.bundle.js"></script>
</body>
</html>
In your webpack config file add
resolve : {
extensions: [".js", ".jsx"]
}
So that you won't need to import your jsx file with extenstion.
Class names should start with Capital letters otherwise methods in react components will not be invoked and also no error will be thrown.
engine.jsx
class Engine extends React.Component{
constructor(){
super();
console.log('Component has been constructed ')
}
render(){
return(
<div>xD</div>
)
}
}
export default Engine;
App.jsx
import Engine from './engine'
render(
<Engine/>,
document.getElementById('root')
);
Please verify https://codesandbox.io/s/D9rpvWWG6
Also you can refer https://github.com/facebook/react/issues/4695

Categories

Resources