I have started to learn ReactJs, I dont have any idea how to debug this. I have a basic app.jsx .
var React = require('react');
var ReactDOM = require('react-dom');
var {Route, Router, IndexRoute, hashHistory} = require('react-router');
var Main = require('Main');
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={Main}>
</Route>
</Router>,
document.getElementById('app')
);
I have written two basic components in my React app now and I nested them.
var React = require('react');
React.createClass({
render: function () {
return (
<h2>Nav Component</h2>
);
}
})
module.exports = Nav;
var React = require('react');
var Nav = require('Nav');
var Main = React.createClass({
render: function () {
return (
<div>
<Nav/>
<h2>Main Component</h2>
</div>
);
}
});
module.exports = Main;
I use webpack
module.exports = {
entry: './app/app.jsx',
output: {
path: __dirname,
filename: './public/bundle.js'
},
resolve: {
root: __dirname,
alias: {
Main: 'app/components/Main.jsx',
Nav: 'app/components/Nav.jsx'
},
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0']
},
test: /\.jsx?$/,
exclude:/(node_modules|bower_components)/
}
]
}
};
and I dont get any errors but browser shows nothing. When I check developer tools I see "Uncaught ReferenceError: Nav is not defined".The files are in correct folders. How can I solve this?
Thanks
If the code you’ve provided is accurate, the problem is that you didn’t actually define a variable called Nav in your nav file. You just called React.createClass without assigning that to the variable Nav. Then you tried to export Nav at the bottom. Assign your createClass calls to variables and it should solve your problem.
Hi because your component definition is wrong it could be like below
class Nav extends React.Component or var Nav = React.createClass({
render: function () {
return (
Nav Component
);
}
})
Related
I am trying to make a SSR react app, but not able to pass props from express to the component.
What mistake am i doing?
server.js
import AppPage2 from './src/project02/LandingPage';
......
......
server.get('/project2',async (req,res)=>{
const context = {data:'test'}
const sheet = new ServerStyleSheet();
const content = ReactDOMServer.renderToString(sheet.collectStyles(
<StaticRouter location={req.url} context={context}>
<AppPage2 state={{"foo":"baar"}}/>
</StaticRouter>)
);
const styles = sheet.getStyleTags();
let html = appShell( 'Project 2', content,' project2.bundle.js',styles)
res.status(200).send(html);
res.end()
})
AppPage2(./src/project02/LandingPage)
import React from 'react';
import {Wrapper,Title} from './styleComponent/testStylePage'
.......
.......
class AppPage extends React.Component {
componentDidMount() {
console.log("{{API}}",this,this.props, this.props.staticContext)
}
render(){
return(
<Wrapper>
<Title>This is project 01 </Title>
</Wrapper>
)
}
}
export default AppPage;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import AppPage from './project02/LandingPage'
ReactDOM.hydrate(
<AppPage></AppPage>,
document.querySelector('#root')
);
webpack.client.conf
const path = require('path');
const glob = require("glob");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const entry = glob.sync("src/*.js")
.reduce((x, y) => Object.assign(x,
{
[y.replace('src/','').replace('.js','')]: `./${y}`,
}
), {});
module.exports = {
target: 'node',
mode: 'development',//development,production
entry: entry,
output: {
filename:'[name].bundle.js',
path: path.resolve(__dirname,'build/public/'),
publicPath: '/build/'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader'
},
},
]
},
plugins: [
// new BundleAnalyzerPlugin()
]
}
I am not able to log console.log("{{API}}",this,this.props, this.props.staticContext) from AppPage2(./src/project02/LandingPage) this page i am sending data from server.js(express)
Your props already passed to your component on Page2, but you're longing it using a function that will never been called,
componentDidMount() is invoked immediately after a component is mounted (inserted into the DOM tree).
in your case, you are not mounting any thing to the DOM, because react will only render your component to html and will not wait for your component to Mount, practically there is no DOM in your NodeJs server, and you're only rendering the component and return it as string, not inserting it to the DOM.
Your props are already there and you can console log them in your class constructor, and in your render method:
class AppPage extends React.Component {
constructor (props){
super(props)
console.log("{{API}}",this,this.props, this.props.staticContext)
}
render(){
//or console log it here
console.log("{{API}}",this,this.props, this.props.staticContext)
return(
<Wrapper>
<Title>This is project 01 </Title>
</Wrapper>
)
}
}
in this state your compoenent will mount and not did mount you can also console log your props using UNSAFE_componentWillMount but as it's name said it's unsafe
ReactJS.org
You can also create your own functions and it will works:
myFunction () {
console.log(this.props.state)
}
myFunction();
I have a problem. I cant refresh my react components/page without getting "Cannot GET /currentPage". I've browsed you for some time now and found a couple of links that could be the solution of my issue:
https://github.com/jintoppy/react-training/blob/master/basic/node_modules/react-router/docs/guides/Histories.md#browserhistory
HashHistory of BrowserHistory. Internet said I should use BrowserHistory for production - but that hashHistory is easier. They are both so effing complicated. I cant for my life figure out how to implement it to my current code.
This is my app.js file:
/*global $:true*/
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';
import './scss/app.scss';
// Component imports
import Home from './components/home';
import Archive from './archive';
// Image import
import loadImg from './images/tits.gif';
class App extends Component {
// Function for anchorlinks
hashLinkScroll() {
const { hash } = window.location;
if (hash !== '') {
// Push onto callback queue so it runs after the DOM is updated, this is required when navigating from a different page so that the element is rendered on the page before trying to getElementById
setTimeout(() => {
const id = hash.replace('#', '');
const element = document.getElementById(id);
if (element) element.scrollIntoView();
}, 100);
}
}
// 1. Render site-loader gif
// 2. React Router component wraps all of the routes we are going to define - Archive and Home. Each route will be identified in a <Route> component. The <Route> component will take two properties: path and component. When a path matches the path given to the <Route> component, it will return the component specified.
render() {
return (
<div>
<div className="loaderSmall">
<img className="loadingImg" src={loadImg} width="400"/>
</div>
<Router history={browserHistory} onUpdate={this.hashLinkScroll}>
<Route path={'/archive'} component={Archive} />
<Route path={'*'} component={Home} />
</Router>
</div>
);
};
// When Component has rendered, window.addEventListener adds event "load" and calls handleLoad function
componentDidMount() {
window.addEventListener('load', this.handleLoad);
}
// Fade out site-loader
handleLoad() {
$(".loaderSmall").delay(500).fadeOut("slow");
}
};
ReactDOM.render (
<App/>,
document.getElementById('app')
)
// Hot Module Replacement API (injecting code)
if (module.hot) {
module.hot.accept();
}
export default App;
..this is my menu component that renders when I am on "/archive" component:
import React, { Component } from 'react';
import { Link } from 'react-router';
//Menu component renders menu Link
class Menu extends Component {
render() {
return (
<header>
<nav>
<ul>
<li><Link to={'/#top'}>Home</Link></li>
<li><Link to={'/#about'}>About</Link></li>
<li><Link to={'/archive'}>Archive</Link></li>
<li className="contactMobile">Contact</li>
<li className="contactWeb"><Link to={'/#contact'}>Contact</Link></li>
</ul>
</nav>
</header>
);
}
}
export default Menu;
..and this is my other menu that renders when i am on root where i want scrollable hashlinks:
import React, { Component } from 'react';
import { Link } from 'react-router';
import Scrollchor from 'react-scrollchor';
//Menu component renders menu Link
class MenuB extends Component {
render() {
return (
<header>
<nav>
<ul>
<li><Scrollchor to="#top" animate={{offset: 20, duration: 800}}>Home</Scrollchor></li>
<li><Scrollchor to="#about" animate={{offset: 0, duration: 800}}>About</Scrollchor></li>
<li><Link to={'/archive'}>Archive</Link></li>
<li className="contactMobile">Contact</li>
<li className="contactWeb"><Scrollchor to="#contact" animate={{offset: 20, duration: 800}}>Contact</Scrollchor></li>
</ul>
</nav>
</header>
);
}
}
export default MenuB;
my webpack.config.js file:
// DEVELOPMENT
const webpack = require('webpack');
const path = require('path');
const entry = [
'webpack-dev-server/client?http://localhost:8080', // bundle the client for webpack-dev-server and connect to the provided endpoint
'webpack/hot/only-dev-server', // bundle the client for hot reloading only- means to only hot reload for successful updates
'./app.js'
]
const output = {
path: path.join(__dirname, 'dist'),
publicPath: '/dist',
filename: 'bundle.min.js'
}
const plugins = [
new webpack.HotModuleReplacementPlugin(), // enable HMR globally
new webpack.NamedModulesPlugin() // prints more readable module names in the browser console on HMR updates
]
const config = {
context: path.join(__dirname, 'src'),
entry: entry,
output: output,
devtool: "inline-source-map",
module: {
rules: [
{
// test: /\.(js|jsx)$/,
// exclude: /node_modules/,
// include: path.join(__dirname, 'src'),
// use: {
// loader: "eslint-loader",
// options: {
// failOnWarning: false,
// failOnError: false
// }
// }
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
use: {
loader: "babel-loader"
}
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: { limit: 10000, name: './images/[name].[ext]' }
}]
},
{
test: /\.(sass|scss)$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
]
},
performance: {
maxAssetSize: 400000000,
maxEntrypointSize: 400000000,
hints: 'warning'
},
plugins: plugins,
externals: {
jquery: 'jQuery'
}
}
module.exports = config
And my webpack.config.prod.js file:
// PRODUCTION
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const entry = {
app: path.join(process.cwd(), 'src/app.js')
}
const output = {
path: path.join(__dirname, 'dist'),
filename: 'bundle.min.js',
}
const plugins = [
new webpack.DefinePlugin({
// 'process.env.NODE_ENV': JSON.stringify('production')
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin({
mangle: false,
compress: {
warnings: false
}
}),
new ExtractTextPlugin('bundle.css'), // creation of HTML files to serve your webpack bundles
new HtmlWebpackPlugin({
template: 'index-template.html'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'bundle',
filename: '[name].common.js'
})
]
const config = {
context: path.join(__dirname, 'src'),
entry: entry,
output: output,
devtool: "source-map",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
use: "babel-loader"
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: { limit: 10000, name: './images/[name].[ext]' } // Convert images < 10k to base64 strings (all in images folder)
}]
},
{
test: /\.(sass|scss)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: (loader) => [ require('autoprefixer')() ]
}
},
'sass-loader',
]
})
}
]
},
plugins: plugins,
externals: {
jquery: 'jQuery'
}
}
module.exports = config;
..I know that there are much better ways to do this than to have two menu components that renders on different pages, but I just did this solution for now .. Problem is that I don't understans how to convert this to HashHistory of BrowserHistory without loosing my logic. Any tips/input would be so goddammit appreciated, been sitting with this for weeks now <3
Cannot GET /currentPage ?
For browserHistory on page refresh ,/currentPage is requested on server side.
At the backend, your server dont defined this path (requested resource).
You need to implement it to fixed Cannot GET issue for page refresh.
Assuming nodejs
app.use(express.static(__dirname));
//will serve index.html for every page refresh.
app.use('*',(req,resp)=>{
res.sendFile(path.resolve(__dirname+'/index.html'))
})
app.listen(someport)
This will load index.html page for every page refresh.
Once index.html is loaded with required JS & react router,
the router will trigger the route and corresponding component is getting rendered.
#Panther solved this. To be able to refresh page in my dev environment, I had to add:
historyApiFallback: {
disableDotRule: true
}
to my webpack dev.server file:
var WebpackDevServer = require('webpack-dev-server');
var webpack = require('webpack');
// requiring my webpack configuration
var config = require('./webpack.config.js');
var path = require('path');
var compiler = webpack(config);
// then spinning up a new dev server with some settings
var server = new WebpackDevServer(compiler, {
hot: true,
filename: config.output.filename,
publicPath: config.output.publicPath,
proxy: {
"/getMail": 'http://localhost:80/magdan/php/mailer.php',
"/getProducts": 'http://localhost:80/magdan/php/products.php'
},
stats: {
colors: true
},
historyApiFallback: {
disableDotRule: true
}
});
// its gonna listen to port 8080
server.listen(8080, 'localhost', function() {
console.log("Starting server on http://localhost:8080");
});
I'm trying to build a React app using some simple methods of building views and components. When I run my webpack dev server I get the following error output:
Module parse failed: /Directory/To/router.js Unexpected token (26:2)
You may need an appropriate loader to handle this file type.
The line it complains about is when I first define my Router handler...
<Route handler={App}>
My full router.js is set as such:
// Load css first thing. It gets injected in the <head> in a <style> element by
// the Webpack style-loader.
import css from './src/styles/main.sass';
import React from 'react';
import { render } from 'react-dom';
// Assign React to Window so the Chrome React Dev Tools will work.
window.React = React;
import { Router } from 'react-router';
Route = Router.Route;
// Require route components.
import { App } from './containers/App';
import { Home } from './containers/Home';
import { StyleGuide } from './containers/StyleGuide';
import { Uploader } from './containers/Uploader';
const routes = (
<Route handler={App}>
<Route name="Home" handler={Home} path="/" />
<Route name="StyleGuide" handler={StyleGuide} path="/styleguide" />
<Route name="Uploader" handler={Uploader} path="/uploader" />
</Route>
)
Router.run(routes, function(Handler) {
return ReactDOM.render(<Handler/>, document.getElementById('app'));
});
In my .babelrc file I have my presets defined with react and es2015
My development webpack looks like this:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: [
'webpack-dev-server/client?http://0.0.0.0:8080',
'webpack/hot/only-dev-server',
'./src/router'
],
devtool: 'eval',
debug: true,
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
resolveLoader: {
modulesDirectories: ['node_modules']
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [
// js
{
test: /\.js$/,
loaders: ['babel'],
include: path.join(__dirname, 'public')
},
// CSS
{
test: /\.sass$/,
include: path.join(__dirname, 'public'),
loader: 'style-loader!css-loader!sass-loader'
}
]
}
};
I've already tried to research this problem. I'm not finding any solutions to this specific instance. I'm curious to find why this is acting like this.
Edit 1
I managed to solve my problem by changing the directory name to my actual source directory and not in public/. But after correcting my mistake I stumbled upon two other errors dealing with my components, perhaps?
I now receive two errors in the browser:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
TypeError: _reactRouter.Router.run is not a function. (In '_reactRouter.Router.run', '_reactRouter.Router.run' is undefined)
I've found that this is commonly caused by not importing/exporting some things correctly. It's either coming from my router.js or my components that share their structure as below:
import React from 'react';
import { Link } from 'react-router';
const Uploader = React.createClass({
//displayName: 'Uploader',
render() {
return (
<div>
<h1>Uploader</h1>
</div>
)
}
});
export default Uploader;
You are exporting Uploader as default but importing it as a named export:
export default Uploader;
import { Uploader } from './containers/Uploader';
// instead do
import Uploader from './containers/Uploader';
Your Router configuration is a bit strange. What version of react-router are you using? Usually you can wrap your <Route> config into a <Router>. See the docs.
I've been trying to get into React and therefore read the official guides, however, I'm not sure how to put components into their own files to reuse them across files.
I've made a very basic React Component which holds an input tag and some configuration with it. I would like to make this input tag a standalone component in its own file. How do I achieve this?
I use Webpack with this configuration:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
}]
}
};
This is the React code:
import React, { Component } from 'react';
export default React.createClass({
getInitialState: function() {
return {text: ''};
},
handleChange: function(e) {
this.setState({text: e.target.value})
},
render() {
return (
<div>
<h1>What's your name?</h1>
<input
type="text"
value={this.state.text}
onChange={this.handleChange}
/>
<h2>Hallo, {this.state.text}</h2>
</div>
);
}
});
Edit: I forgot the index.js:
import React from 'react';
import { render } from 'react-dom';
import App from './Components/App';
render(<App />, document.getElementById('root'));
Thanks.
You will want to create an input component and pass your state and handle change function as props to the component.
Input Component :
import React, {Component} from 'react';
var Input = React.createClass({
handleChange: function(e) {
this.props.handleChange(e.target.value);
}
render() {
return (
<input
type="text"
value={this.props.text}
onChange={this.handleChange} />
)
}
});
export default Input;
Your current component (with the input component added in):
import React, { Component } from 'react';
import Input from './path_to_inputComponent';
export default React.createClass({
getInitialState: function() {
return {text: ''};
},
handleChange: function(text) {
this.setState({text: text})
},
render() {
return (
<div>
<h1>What's your name?</h1>
<Input text={this.state.text} handleChange={this.handleChange} />
<h2>Hallo, {this.state.text}</h2>
</div>
);
}
});
So what will happen is, this.state.text will be passed as the text prop to Input which will set the value of the input. This will allow the input component to be used in multiple places and have a different value in each place that it is used. Also, when the onChange event is fired from the input, it will call the function that handleChange function that is passed to it as a prop. Therefore, it will call the function in the parent component and the state will be updated in the parent component.
I’m trying to get react router dynamic routing to work by following this example: https://github.com/rackt/react-router/tree/master/examples/huge-apps
Here’s my setup:
webpack.config.js:
module.exports = {
devtool: 'inline-source-map',
entry: './js/app.js',
output: {
path: '../public',
filename: 'test-app.js',
chunkFilename: '[id].chunk.js',
publicPath: '/public/'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: [
'es2015',
'react'
]
}
}
]
}
./js/app.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { createHistory, useBasename } from 'history';
import { Router } from 'react-router';
const history = useBasename(createHistory)({
basename: '/'
});
const rootRoute = {
component: 'div',
childRoutes: [{
path: '/',
component: require('./components/App')
}]
};
ReactDOM.render(
<Router history={history} routes={rootRoute} />,
document.getElementById('root')
);
./components/App.js:
import React from 'react';
console.log('testing');
export default class App extends React.Component {
render() {
console.log('App');
return (
<div>
App!
</div>
)
}
}
index.html:
<!doctype html>
<html>
<head>
<title>Test App</title>
</head>
<body>
Hello
<div id="root"></div>
<script src="public/test-app.js"></script>
</body>
</html>
When I run the server, I see Hello displayed from index.html, I also see console.log('testing') from App.js, but the actual App.js component does not render. Any ideas why?
Thanks!
EDIT:
If I change ./components/App.js to ES5 syntax below, it works! Why is that? Does react router's component: require('./components/App') not work with ES6?
var React = require('react');
var App = React.createClass({
render: function() {
return (
<div>
App!
</div>
)
}
});
module.exports = App;
I think, you are using Babel 6, where they changed commonjs require syntax.
Now, you need to add the default:
component: require('./components/App').default
I had the same problem, finally found how to make it work.