React router shows blank page - node.js

I am trying to get started with react-router.
import React from 'react';
import ReactDOM from 'react-dom';
import HelloWorld from './pages/HelloWorld';
import {Router, Route, IndexRoute, hashHistory,browserHistory} from "react-router";
...
const app = document.getElementById('root')
ReactDOM.render(<HelloWorld/>, app);
Here dummy class HelloWorld:
import React, { Component } from 'react';
class HelloWorld extends Component {
render(){
return(<h1> HelloWorld </h1>);
}
}
export default HelloWorld;
Using this setting everything works out fine. However, using routes I end up having a blank page.
ReactDOM.render(
<Router history = {hashHistory}>
<Route path ="/" component={HelloWorld}>
</Route>
</Router>,
app);
Where is the mistake? I searched stackoverflow but no answer seems to be suitable.
Whats really weird for me, is that the following code also results in a blank page:
const Routes = () => (
<Router history = {browserHistory}>
<Route path ="/" render={ () => (<h1> HelloWorld </h1>) } />
</Router>
);
const app = document.getElementById('app')
ReactDOM.render(<Routes/>, app);

You're using using the V4 in a V3 way.
Instead of
import {Router, Route, IndexRoute, hashHistory,browserHistory} from "react-router";
Import dependencies in this way:
import {BrowserRouter as Router, Route} from "react-router";
import createHistory from "history/createBrowserHistory" // browser history moved into a standalone package since v4.

Ok "one" solution is:
import {BrowserRouter as Router, Route, IndexRoute,hashHistory,browserHistory} from "react-router-dom";
...
const Routes = () => (
<Router history = {browserHistory}>
<Route path ='/' component={ Layout } />
</Router>
);
const app = document.getElementById('app')
ReactDOM.render(<Routes/>, app);

99% sure your issue is that your tag has a relative link. Make it absolute.
<!-- do this -->
<script src="/static/bundle.js"></script>
<!-- not -->
<script src="static/bundle.js"></script>
<!-- or -->
<script src="./static/bundle.js"></script

Related

Creating admin user in MERN

I want to create an admin user in my MERN application, I created a user model on back-end and put isAdmin there. Now I want to protect some routes on back-end. On front-end I need to protect normal user to access admin panel, which is accessible when click on NavLink.
User schema:
Signup controller:
Front end routes:
you can use switch route of react routes like that.
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Route,
browserHistory,
Switch
} from 'react-router-dom';
import App from './app/App';
import Welcome from './app/Welcome';
import NotFound from './app/NotFound';
const isAdmin = false; // flag of current user login
const Root = () => (
<Router history={browserHistory}>
<Switch>
{{isAdmin ? <Route exact path="/admin" component={Admin}/> : null }}
{{isAdmin ? <Route exact path="/admin/new" component={AdminNew}/> : null }}
<Route component={NotFound}/>
</Switch>
</Router>
);
ReactDOM.render(
<Root/>,
document.getElementById('root')
);

What's wrong with my routing in my react application?

I have a React application that I just deployed to my server and now the routing isn't working as expected. I need some help figuring it out.
When running locally, this works:
<button className="welcome-buttons"
onClick={() => window.location.href = 'http://localhost:3000/services'}>
Read More <i className="fas fa-arrow-alt-circle-right"></i>
</button>
I would click on the button and it would route to http://localhost:3000/services. Then when I was ready to deploy, I changed this to http://www.assertivesolutions.ca/services, created a build and uploaded it to my server. I would go to my site (http://www.assertivesolutions.ca) and it would load fine, but when I clicked on the button, I get taken to a page that says Cannot GET /services.
I'm not sure why this is. Maybe I can't just replace localhost:3000 with www.assertivesolutions.ca in the code. But what is the right way to do it?
This is what I have in app.js
import React, { Component } from 'react';
import './App.scss';
import './Home.scss';
import Header from './Header/Header';
import Banner from './Banner/Banner';
import Welcome from './Welcome/Welcome';
import MainFocus from './MainFocus/MainFocus';
import WhatWeDo from './WhatWeDo/WhatWeDo';
import OurBlog from './OurBlog/OurBlog';
import OurClients from './OurClients/OurClients';
import ContactUs from './ContactUs/ContactUs';
import Footer from './Footer/Footer';
import smoothscroll from 'smoothscroll-polyfill';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Blog from './Blog/blog';
import OurServices from './OurServices/OurServices';
import SideMenu from './SideMenu/SideMenu';
class App extends Component {
render() {
smoothscroll.polyfill();
return (
<Router>
<Switch>
<Route path="/" exact>
<div className="app-master-container">
<SideMenu pageWrapId={'page-wrap'} outerContainerId={'outer-container'} />
<div className="header"><Header /></div>
<Banner />
<Welcome />
<MainFocus />
<WhatWeDo />
<OurBlog />
<OurClients />
<ContactUs />
<Footer />
</div>
</Route>
<Route path="/blog">
<Blog/>
</Route>
<Route path="/services">
<OurServices/>
</Route>
</Switch>
</Router>
);
}
}
export default App;
On the server, I'm running node and bouncy to handle the routing to each website I host, like this:
const bouncy = require('bouncy');
const express = require('express');
const path = require('path');
const { create, engine } = require('express-handlebars');
bouncy(function(req, bounce) {
const host = req.headers.host;
console.log(`host=${host}`);
if (host === 'shahspace.com' || host === 'www.shahspace.com') {
if (req.url.includes('/music%20mixes/')) bounce(8002);
else bounce(8000);
}
if (host === 'assertivesolutions.ca' || host === 'www.assertivesolutions.ca') bounce(8001);
if (host === 'fmshahdesign.com' || host === 'www.fmshahdesign.ca') bounce(8003);
}).listen(80);
const fmsApp = express();
fmsApp
.use(express.static(path.join(__dirname, 'fmshahdesign.com')))
.listen(8003);
const assertSolApp = express();
assertSolApp
.use(express.static(path.join(__dirname, 'assertivesolutions.ca')))
.listen(8001);
const musicMixApp = express();
musicMixApp.engine('.hbs', engine({
extname: 'hbs',
defaultLayout: false
}));
musicMixApp.set('view engine', 'hbs');
musicMixApp.set('views', path.join(__dirname, 'shahspace.com/music mixes/views'));
/****** more code for handling music mix app ********/
In other words, all requests come in on port 80 where the node router is listen, and then it checks the host to see which website is being requested. That's where bouncy comes in. It bounces the request to the appropriate port corresponding to the requested website. assertivesolutions.ca is on port 8001 so it bounces it there. Each site has an app created with express which handles the request on the appropriate port.
This works as long as I go to www.assertivesolutions.ca but as soon as I go to www.assertivesolutions.ca/services, it get the Cannot GET /services message. I would create a services folder in the assertivesolutions.ca folder (where the assertSolApp directs requests to) but the contents were created by the build (which I would think should be able to handle requests for /services) so I don't think I should mess with that.
Can anyone see the problem? Thanks.
If you're not sure about your url . Instead of Redirect to Another Webpage with vanilla javascript you can use react router (which you're already using and it seems version 5 ) .
Just add it to your component like this :
in functional components :
import { useHistory } from "react-router-dom";
..............
let history = useHistory();
<button className="welcome-buttons"
onClick={() => history.push("/services")}>
Read More <i className="fas fa-arrow-alt-circle-right"></i>
</button>
in class components :
You can get access to the history object’s properties via the withRouter which is a higher-order component. you can do something like this :
import { withRouter } from "react-router-dom";
class Example extends React.Component {
render() {
return (
<div>
.........
<button className="welcome-buttons"
onClick={() => this.props.history.push("/services")}>
Read More <i className="fas fa-arrow-alt-
circle-right"></i>
</button>
</div>
);
}
}
export default withRouter(Example);
this is a simple codesandbox showing how o implement withRouter
You need to write the .htaccess file in the server root directory.
Check this link

How to use proxy in production mode with npm like proxy parameter in package.json?

I think i need to explain a little bit more about my issue.
I have setup a react app and a typeorm backend.
In my react app i set the proxy parameter to 'localhost:3001' which is my backend. (my react app runs on 'localhost:3001').
This works like a charm IN DEVELOPEMENT.
However when it comes to production (for example when i build my react app and serve it with npm serve -l 3000) i am forced to do the proxying myself.
I googled for this and i think the first few answers to this topic showed me that express is the way to go. So i googled more and found a package called 'http-proxy-middleware'.
This is my code:
const { createProxyMiddleware } = require('http-proxy-middleware')
var app = require('express')();
const port = 80;
var apiProxy = createProxyMiddleware('/api', { target: 'http://localhost:3001' });
var normalProxy = createProxyMiddleware('/', { target: 'http://localhost:3000' });
app.use(apiProxy);
app.use(normalProxy);
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
It works but not like i want it to.
When i make a call to 'http://localhost/api' it proxys to my backend.
When i make a call to 'http://localhost/' it proxys to my react app.
Now when i try to call 'http://localhost/db/home' for example it gives me an 404 Error (it should proxy to 'http://localhost:3000').
I think it also has to do with the react dom router package that i use.
Because of that here is the content of my 'App.tsx':
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import 'bootstrap/dist/css/bootstrap.css';
import './App.scss';
import MainTab, { IMainTabProps } from './staticTabs/MainTab/MainTab';
import { MainTab as DBMainTab } from './dashboardTabs/MainTabs/MainTab/MainTab';
import Tab404 from './staticTabs/Tab404/Tab404';
import StaticTabsLayout from './staticTabs/StaticTabsLayout';
import DashboardTabsLayout from './dashboardTabs/DashboardTabsLayout';
import Profile from './dashboardTabs/MainTabs/Profile/Profile';
import Settings from './dashboardTabs/MainTabs/Settings/Settings';
function App() {
return (
<Router>
<Switch>
<Route path="/db/home">
<DashboardTabsLayout>
<DBMainTab />
</DashboardTabsLayout>
</Route>
<Route path="/db/me">
<DashboardTabsLayout>
<Profile />
</DashboardTabsLayout>
</Route>
<Route path="/db/settings">
<DashboardTabsLayout>
<Settings />
</DashboardTabsLayout>
</Route>
<Route path="/db/">
<DashboardTabsLayout>
<DBMainTab />
</DashboardTabsLayout>
</Route>
<Route path="/index.html">
<StaticTabsLayout>
<MainTab />
</StaticTabsLayout>
</Route>
<Route path="/verify/:UserID/:VerifyID" component={(props: JSX.IntrinsicAttributes & JSX.IntrinsicClassAttributes<MainTab> & Readonly<IMainTabProps> & Readonly<{ children?: React.ReactNode; }>) => <StaticTabsLayout><MainTab verify={true} {...props} /></StaticTabsLayout>} />
<Route exact path="/">
<StaticTabsLayout>
<MainTab />
</StaticTabsLayout>
</Route>
<Route component={Tab404} />
</Switch>
</Router>
);
}
export default App;
Update
I also tried calling 'http://localhost:3000/db' in my Browser and this gives me also an 404. So i think it could also possibly be that my 'react-router-dom' code doesn't work.
So i found the problem myself.
I had the feeling that it has something to do with the react app it self. So i looked up the deployment section under the create-react-app-website and i found out that i used the serve -l 3000 command in build directory to host my frontend. Then i saw in the documentation that i should use serve -s build -l 3000 outside of my build directory to serve it correctly.
Thanks also to #eol's answer as it probably would be the next thing that might had helped if it wasn't the problem that i had with serve.
Also if your'e problem was the same as mine (with serve) you just need to use a middleware proxy with '/' put no one with '*'. So it would look like this:
const { createProxyMiddleware } = require('http-proxy-middleware')
var app = require('express')();
const port = 80;
var apiProxy = createProxyMiddleware('/api', { target: 'http://localhost:3001' });
var frontendProxy = createProxyMiddleware('/', { target: 'http://localhost:3000' });
app.use(apiProxy);
app.use(frontendProxy);
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})

React TypeError: location is undefined

I am currently working on creating a boilerplate react application. I have been following these tutorials, but I haven't been able to get past the first tutorial.
I created my app with create-react-app
When I try to run my app, it compiles, but I get an error that says:
TypeError: location is undefined
This error points to the ReactDOM.render( line in this code
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
registerServiceWorker();
If it is relevant, here is my app.js file as well
import React from 'react';
import { Route } from 'react-router-dom';
import { HomePage, LoginPage } from "./components/pages";
import { Grid } from 'react-flexbox-grid';
import 'react-flexbox-grid/dist/react-flexbox-grid.css';
const App = () => (
<Grid fluid>
<Route path='/' exact component={HomePage} />
<Route path='/login' exact component={LoginPage} />
</Grid>
)
export default App;
I've also tried creating a new react app. For the first time, I ejected the app so that I could add css modules, then when I tried to build it again, I used custom react scripts. The problem began about when I ejected the app, but I'm sure if that was the problem because I did rebuild it and copy the src folder over to the new app.
Finally, here is a screenshot of the errors that I am getting.
I've been stuck on this problem for the past 2.5 days, so any help would be greatly appreciated. Thank you so much in advance.
UPDATE: Hey guys. I'm an idiot. The <Link> component uses a to attribute unlike the a tag's href. That was my problem. Really. Well there goes 3 days down the drain and all of your time. Thank you for your help anyway, I appreciate all that you have done.
EDIT - Explanation of the Resolution (as described in #Vishah's answer)
I'm adding an edit here in hopes of helping anyone who comes across this.
The source of the issue was the Links components included "href" attributes instead of "to" attributes.
- <Link href='/'>Home</Link>
+ <Link to='/'>Home</Link>
Additionally, it's worth noting the "href" didn't throw an attribute error because lowercase attributes are still valid dom in React ^16.2.
Here's the commit on his repo: https://github.com/vishalmshah/MERNStackBoilerplate/commit/73fb3fe2e39ffa870fb91bd8b3592887886e3dbb
This was not the source of the issue
I think I see the issue. BrowserRouter uses the location object to keep track of where you are, your history, and possibly other locations the app will navigate to.
BrowserRouter Routes require being given location object which they can use to compare their path value to.
You've got your Route's wrapped by your App object without passing the location object down.
Try passing location through your app:
const App = ({ location }) => (
Subsequently you may have to access the location in the Routes:
<Route location={location} ...
This example is where I got the information from:
https://github.com/Remchi/bookworm-react/blob/master/src/App.js
UPDATE: Hey guys. I'm an idiot. The component uses a to attribute unlike the a tag's href. That was my problem. Really. Well there goes 3 days down the drain and all of your time. Thank you for your help anyway, I appreciate all that you have done.
One thing I notice immediately is how you are importing the components...
import { HomePage, LoginPage } from "./components/pages";
You can not do this... Instead:
import HomePage from './components/pages/HomePage';
import LoginPage from './components/pages/LoginPage';
Also, you should not install react-router but just react-router-dom...
Here is the App.js
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import HomePage from './HomePage';
import LoginPage from './LoginPage';
const App = () => (
<Switch>
<Route path="/" component={HomePage} exact={true} />
<Route path="/login" component={LoginPage} exact={true} />
</Switch>
);
export default App;
And here is the Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'),
);
registerServiceWorker();
Note: I did not create the pages directory and am also using Switch... (docs: https://reacttraining.com/react-router/web/api/Switch)

react router - Router.js:111Uncaught TypeError: Cannot read property 'getCurrentLocation' of undefined

I've been following this tutorial to get React Router working https://scotch.io/tutorials/routing-react-apps-the-complete-guide ... yet when I try and utilise any function of react router - it gives me this:
Router.js:111Uncaught TypeError: Cannot read property
'getCurrentLocation' of undefined
at Object.createTransitionManager (localhost:8080/public/bundle.js:22730:14)
at Object.componentWillMount (localhost:8080/public/bundle.js:22737:36)
at localhost:8080/public/bundle.js:15709:24
at measureLifeCyclePerf (localhost:8080/public/bundle.js:15436:13)
at ReactCompositeComponentWrapper.performInitialMount (localhost:8080/public/bundle.js:15708:10)
at ReactCompositeComponentWrapper.mountComponent (localhost:8080/public/bundle.js:15619:22)
at Object.mountComponent (localhost:8080/public/bundle.js:8009:36)
at ReactCompositeComponentWrapper.performInitialMount (localhost:8080/public/bundle.js:15732:35)
at ReactCompositeComponentWrapper.mountComponent (localhost:8080/public/bundle.js:15619:22)
at Object.mountComponent (localhost:8080/public/bundle.js:8009:36)
I've tried using webpack-dev-server as well... and still no joy - same issue. I can't find any other mention of this error... what could be the issue?
import React, { Component } from 'react';
import { render } from 'react-dom';
import {Router, Route} from 'react-router';
class Home extends Component {
render(){
return (<h1>Hello</h1>);
}
}
render(
<Router>
<Route path="/" component={Home}/>
</Router>,
document.getElementById('container')
);'
yeah, i test it out, you need to pass history={ browserHistory } to your Router.
render(
<Router history={ browserHistory }>
<Route path="/" component={Home}/>
</Router>,
document.getElementById('container')
);
and don't forget import browserHistory:
import { Router, Route, browserHistory, Link, IndexRoute } from 'react-router';

Resources