So, my app, after being wrapped in a class, no longer renders to the screen, and no errors are issued. Just a blank screen is displayed.
What am I overlooking here?
webpack.config
var path = require('path');
var webpack = require('webpack');
const Dotenv = require('dotenv-webpack');
module.exports = {
devtool: 'source-map',
entry: [
'webpack-hot-middleware/client',
'./client/index'
],
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new Dotenv({
path: './.env', // Path to .env file (this is the default)
safe: true // load .env.example (defaults to "false" which does not use dotenv-safe)
})
],
module: {
rules: [
// js
{
test: /\.js$/,
use: ['babel-loader'],
include: path.join(__dirname, 'client')
},
// CSS
{
test: /\.styl$/,
include: path.join(__dirname, 'client'),
use: [
'style-loader',
'css-loader',
'stylus-loader'
]
}
]
}
};
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import app from './app.js';
ReactDOM.render (
<app />,
document.getElementById('root')
)
app.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute, Redirect } from 'react-router'
import 'babel-polyfill';
import { ApolloProvider, graphql, gql } from 'react-apollo';
import client from './apolloClient';
import App from './components/App';
import Single from './components/Single';
import PhotoGrid from './components/PhotoGrid';
import LoginUser from './components/LoginUser';
import css from './styles/style.styl';
import store, { history } from './store';
import Raven from 'raven-js';
import { sentry_url } from './data/config';
if(window) {
Raven.config(sentry_url).install();
}
import * as OfflinePluginRuntime from 'offline-plugin/runtime';
if (process.env.NODE_ENV === 'production') {
OfflinePluginRuntime.install();
}
class app extends React.Component {
render () {
return (
<ApolloProvider store={store} client={client}>
{ /* Tell the Router to use our enhanced history */ }
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={PhotoGrid} />
<Route path="/view/:postId" component={Single}></Route>
<Route path="/login" component={LoginUser}></Route>
</Route>
</Router>
</ApolloProvider>
)
}
}
export default app;
But if I remove the class, as follows, and specify app.js as the entry: point in my webpack.config, then the app renders correctly:
render(
<ApolloProvider store={store} client={client}>
{ /* Tell the Router to use our enhanced history */ }
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={PhotoGrid} />
<Route path="/view/:postId" component={Single}></Route>
<Route path="/login" component={LoginUser}></Route>
</Route>
</Router>
</ApolloProvider>,
document.getElementById('root')
);
All react classes in jsx must have a capital first letter. You need to update your index.js accordingly
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app.js';
ReactDOM.render (
<App />,
document.getElementById('root')
)
If you were to look at the html output of your code you would likely see <app></app> where you expected your component to be inserted
what about try stateless component:
export default function App() {
return (
<ApolloProvider store={store} client={client}>
{ /* Tell the Router to use our enhanced history */ }
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={PhotoGrid} />
<Route path="/view/:postId" component={Single}></Route>
<Route path="/login" component={LoginUser}></Route>
</Route>
</Router>
</ApolloProvider>
)
}
Related
I'm starting a new project using React Router Dom v6 and I'm in trouble with one of the first steps: setting the routes for the App.
I just created two pages: AuthPage and DashboardPage and I would like to be able of rendering both of them if, from the browser, I navigate to:
localhost:PORT/ : should render DashboardPage
localhost:PORT/auth: should render AuthPage
but right no the only page rendered is DashboardPage even if I try to navigate to non-existing routes.
This is my code so far:
main.tsx
import { createRoot } from 'react-dom/client'
import { MemoryRouter as Router } from 'react-router-dom'
import { ThemeProvider } from '#mui/material/styles'
import { theme } from './theme'
import App from './App'
const root = createRoot(document.getElementById('root') as HTMLElement)
root.render(
<ThemeProvider theme={theme}>
<Router>
<App />
</Router>
</ThemeProvider>
)
App.tsx
import { Route, Routes } from 'react-router-dom'
import AuthPage from './pages/AuthPage'
import DashboardPage from './pages/DashboardPage'
import NotFoundPage from './pages/NotFoundPage'
import { routes } from './routes'
function App() {
return (
<Routes>
<Route path={routes.dashboard.url} element={<DashboardPage />} />
<Route path={routes.auth.url} element={<AuthPage />} />
<Route path={routes.notFound.url} element={<NotFoundPage />} />
</Routes>
)
}
export default App
routes.ts
export const routes = {
auth: {
url: '/auth'
},
dashboard: {
url: '/'
},
notFound: {
url: '*'
}
}
Use BrowserRouter instead of MemoryRouter :
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import { ThemeProvider } from '#mui/material/styles'
import { theme } from './theme'
import App from './App'
const root = createRoot(document.getElementById('root') as HTMLElement)
root.render(
<ThemeProvider theme={theme}>
<BrowserRouter>
<App />
</BrowserRouter>
</ThemeProvider>
)
As I know, exact option doesn't supported in react-router v6.
Try to use index option.
<Route path="/*">
<Route index element={< DashboardPage />} />
<Route path={routes.auth.url} element={<AuthPage />} />
// ... other routes
</Route>
I have an app which is within a sub folder of my primary domain. So Test.com is my domain and my app is in a folder called 'Player' in that domain i.e Test.com/player.
The problem is React Router points to Test.com when it needs to point to Test.com/player.
The other issue is my index file is in a folder called 'public'.
How do I do this in React Router 4/htacess?
Thanks
App
import React from "react";
import {render} from "react-dom";
import {BrowserRouter, Route, Switch, hashHistory} from "react-router-dom";
import Nav from "./components/Nav";
import Home from "./components/Home";
import About from "./components/About";
import Contact from "./components/Contact";
class App extends React.Component {
render() {
return (
<BrowserRouter history={hashHistory}>
<div>
<Nav />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
<Route render={() => {
return <h1>Not Found!</h1>
}} />
</Switch>
</div>
</BrowserRouter>
);
}
}
render(<App />, document.getElementById("main"));
Webpack
const webpack = require("webpack");
module.exports = {
entry: {
filename: "./app/app.js"
},
output: {
filename: "./app/build/bundle.js"
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
query: {
presets: ["es2015", "react"]
}
}
]
},
devServer: {
inline: true,
port: 5000,
contentBase: "./public",
historyApiFallback: true,
}
}
According to React Router Docs, BrowserRouter has
basename: string The base URL for all locations. If your app is served
from a sub-directory on your server, you’ll want to set this to the
sub-directory. A properly formatted basename should have a leading
slash, but no trailing slash.
you can use
class App extends React.Component {
render() {
return (
<BrowserRouter history={hashHistory} basename="/player">
<div>
<Nav />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
<Route render={() => {
return <h1>Not Found!</h1>
}} />
</Switch>
</div>
</BrowserRouter>
);
}
}
You also need those properties on your webpack.config.js
module.exports = {
entry : 'your entry',
output : {
path : 'your path',
filename : 'your filename',
publicPath : '/' //ADD THIS LINE (either / or /player will work)
},
devServer : {
historyApiFallback : true // ADD THIS LINE
}
}
import {Route, IndexRoute} from 'react-router'
import App from './App'
import Home from './Home'
import Repos from './Repos'
import Repo from './Repo'
import About from './About'
module.exports = (
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="/repos" component={Repos}>
<Route path="/repos/:userName/:repoName" component={Repo} />
</Route>
<Route path="/about" component={About}/>
</Route>
)
I didn't expect to have to import React here. Of course, the fix is easy. I just need to add the following:
import React from 'react'
What is puzzling to me is that React is not explicitly used in the code sample I pasted above. I guess it is being required when the Babel/JSX code is transpiled to JavaScript?
Could you tell me exactly why am I required to import React here?
You're correct, the code transpiled by Babel will use React.
You can check for yourself using the "try it out" feature of the Babel website to see what your code will be transpiled to.
In your case, you'll get
"use strict";
module.exports = React.createElement(
Route,
{ path: "/", component: App },
React.createElement(IndexRoute, { component: Home }),
React.createElement(
Route,
{ path: "/repos", component: Repos },
React.createElement(Route, { path: "/repos/:userName/:repoName", component: Repo })
),
React.createElement(Route, { path: "/about", component: About })
);
As you can see, React.createElement is called multiple times.
I am going over a routing lessons for React
After lots of attempts, I got a working application, I can use:
var react = require("react");
var Render = require('react-dom');
Render((
<Router history={hashHistory}>
<Route path="/about" component={About}/>
</Router>
), document.getElementById('app'))
However majority of the examples on the web are using import statements, so for example:
import { Router, Route, hashHistory } from 'react-router'
render((
<Router history={hashHistory}>
<Route path="/" component={App}/>
</Router>
), document.getElementById('app'))
Produces following error in my broswer:
(render is not defined).
This is my web.pack.config:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: [
'./src/app.js'
],
output: {
path: path.join(__dirname, 'public/js'),
filename: 'app.built.js'
},
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?
presets[]=es2015&presets[]=react'
}
]
}
}
What do I have to do so I can start using import statements?
The error is because you are not importing the ReactDOM. The best way to do it is
import React from "react";
import ReactDOM from "react-dom";
import { Router, Route, IndexRoute, hashHistory } from "react-router";
import App from "./App";
const app = document.getElementById('app');
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}></Route>
</Router>, app);
Considering that you have a component called App in the same directory like this:
App.js
import React from "react";
export default class App extends React.Component {
render() {
return (
<div>My App!</div>
);
}
}
it's my first project that use react,react-router,react-hot-loader,webpack-dev-server and webpack. when I change the code in react component, the hot-loader become effective, but at the same time, the console tell me a warning:
You cannot change 《Router routes》; it will be ignored.
I don't know how to solve this issue.there is code:
webpack code:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'source-map' ,
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./jsx/index'
],
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
publicPath: '/public/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js', '.jsx', 'json']
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['react-hot', 'babel'],
}]
},
watch:true
};
index code:
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Route, Link } from 'react-router'
import App from './index/app'
import About from './index/about'
import Inbox from './index/inbox'
class Routers extends React.Component {
render() {
return (
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>
</Router>
);
}
}
ReactDOM.render(<Routers />, document.getElementById('root'));
thank you !!!!
Only thing you need to do, it's to throw <Route /> out of render() method.
So, there are many ways to solve this issue.
Most Official way is what #Stormy say.
My solution like this:
const routes = (
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>
)
// Don't let <Route> in render() method
class Routers extends React.Component {
render() {
return (
<Router>
{ routes }
</Router>
);
}
}
Try to use this configuration
https://github.com/reactjs/react-router/issues/2704#issuecomment-170940448
const routeConfig = [
{ path: '/:locale',
component: App,
indexRoute: { component: NewsCardsContainer },
...
}
];
return (
<IntlProvider key="intl" {...intlData}>
<Router history={history} routes={routeConfig} />
</IntlProvider>
)
Stormy's suggestion of using <Router routes={Routes}/> worked for me. Here are my warning free code snippits with react hot module replacement:
./index.js
import './globals';
import React from "react";
import ReactDOM from "react-dom";
import { AppContainer as HotContainer } from "react-hot-loader";
import { browserHistory } from 'react-router';
import Routes from "./components/Routes.jsx";
const render = function() {
let Router = require('react-router').Router;
ReactDOM.render(
<HotContainer>
<Router history={browserHistory} routes={Routes}/>
</HotContainer>,
document.getElementById('react-container'),
);
};
render();
if( module.hot ) {
module.hot.accept('./components/Routes', () => {
render();
});
}
./components/Routes.jsx
import React from "react";
import { Route, IndexRoute } from "react-router";
import App from "./App.jsx";
import Graphs from "./graphs/Graphs.jsx";
import Trends from "./trends/Trends.jsx";
import Patterns from "./patterns/Patterns.jsx";
const Routes = (
<Route path="/" component={App}>
<IndexRoute component={Graphs}/>
<Route path="graphs" component={Graphs}/>
<Route path="trends" component={Trends}/>
<Route path="patterns" component={Patterns}/>
</Route>
);
export default Routes;
The router actually should never change, so you should be able to just return false for shouldComponentUpdate() in this case.
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Route, Link } from 'react-router'
import App from './index/app'
import About from './index/about'
import Inbox from './index/inbox'
class Routers extends React.Component {
shouldComponentUpdate(){
return false;
}
render() {
return (
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>
</Router>
);
}
}
My Solution is change "Reflux.Component" to "React.Component"
class AppRouter extends Reflux.Component {
constructor(props){
super(props);
this.store = AuthStore;
}
requireAuth (nextState, replace, callback) {
if (nextState.location.pathname != '/login' && nextState.location.pathname != '/logout') {
ActionsAuth.jwt.refresh();
}
const token = UtilsJWT().getToken();
if (token){
if (nextState.location.pathname == '/login') {
window.location.href = '/main';
}
callback();
}else{
if (nextState.location.pathname != '/login') {
window.location.href = '/login';
}
}
}
verifyAuth (nextState, replace, callback) {
const token = UtilsJWT().getToken();
if (token){
if (nextState.location.pathname == '/login') {
window.location.href = '/main';
}
callback();
}else{
if (nextState.location.pathname != '/login') {
window.location.href = '/login';
}
callback();
}
}
render(){
return (
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Login} onEnter={ this.verifyAuth }/>
<Route path="login" component={Login} onEnter={ this.verifyAuth }/>
<Route path="main" component={Main} onEnter={ this.requireAuth }/>
<Route path="logout" component={Logout} onEnter={ this.requireAuth }/>
<Route path="local-sync" component={LocalSync} onEnter={ this.requireAuth }/>
<Route path="*" component={Login} onEnter={ this.verifyAuth }/>
</Route>
</Router>
)
}
}
i have the same issue,my Solution is change "import { Router, Route, Link } from 'react-router'" to "import {HashRouter, Route, Link} from 'react-router-dom'"
my code:
ReactDOM.render((
<HashRouter>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/login">Login</Link></li>
</ul>
<hr/>
<Route path="/" exact component={createComponent(Home)}/>
<Route path="/login" component={createComponent(Login)}/>
</div>
</HashRouter>
), document.getElementById('root'));
I know this is an old question, but someone might find this useful. I tried a lot of stuff and what finally worked for me is:
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Route, Link } from 'react-router'
import App from './index/app'
import About from './index/about'
import Inbox from './index/inbox'
class Routers extends React.Component {
private routes = (
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>
);
render() {
return (
<Router>
{this.routes}
</Router>
);
}
}