Why does react router work on localhost but will not work after Heroku deployment? - react-native

there are a few posts like this and I have tried other solutions such as adding a .htaccess file, and adding 'process.env.PUBLIC_URL' ahead of each route to get the relative route location, but nothing seems to be working with the new react-router-dom package which has been released...
The application will load the '/' login page no problem on startup in heroku, and in there a direct will move to another page, however after successful login I use 'window.location.assign("/Home")' to try to auto navigate back to the home page. This gets a 404 error.
Similarly, manually adding locations into the top bar also give 404 errors..
I have tried the fixes provided in other posts, but they are all for the old react-router-dom package (before they moved away from switch and started using BrowserRouter).
Can anyone help figure out why my router won't identify addresses added to the window location??
The application is currently deployed at https://dashboard.heroku.com/apps/octowatch-scratch
App.js
import React from "react";
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { createTheme, ThemeProvider } from '#mui/material/styles';
import AboutKPI from './pages/AboutKPI';
import Login from './pages/Login';
import BreachComposition from './pages/BreachComposition';
import BreachesPerWard from './pages/BreachesPerWard';
import Dashboard from './pages/Dashboard';
import AddAccount from './pages/AddAccount';
import ManageAccounts from './pages/ManageAccounts';
import OverallBreaches from './pages/OverallBreaches';
import AddData from './pages/AddData';
import Home from './pages/Home';
import { lightGreen, brown } from '#mui/material/colors';
import './App.css';
const theme = createTheme({
palette: {
primary: {main: lightGreen[900]},
secondary: {main: brown[500]},
},
});
function App() {
return (
<BrowserRouter>
<ThemeProvider theme={theme}>
<Routes>
<Route exact path="/" element = {<Login/>} />
<Route exact path="/AboutKPI" element = {<AboutKPI/>} />
<Route exact path="/BreachComposition" element = {<BreachComposition/>} />
<Route exact path="/BreachesPerWard" element = {<BreachesPerWard/>} />
<Route exact path="/Login" element = {<Login/>} />
<Route exact path="/Home" element = {<Home/>} />
<Route exact path="/Dashboard" element = {<Dashboard/>} />
<Route exact path="/AddAccount" element = {<AddAccount/>} />
<Route exact path="/ManageAccounts" element = {<ManageAccounts/>} />
<Route exact path="/OverallBreaches" element = {<OverallBreaches/>} />
<Route exact path="/AddData" element = {<AddData/>} />
</Routes>
</ThemeProvider>
</BrowserRouter>
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
Login Page ()
import React, { useState } from "react";
import { Grid,Paper, Avatar, TextField, Button, Typography } from '#mui/material'
import FormControlLabel from '#mui/material/FormControlLabel';
import Checkbox from '#mui/material/Checkbox';
import Api from "../api.js"
import LockIcon from '#mui/icons-material/Lock';
import { Link } from 'react-router-dom';
export default function Login(breachesCallback) {
const paperStyle={padding :20,height:'70vh',width:280, margin:"20px auto"}
const avatarStyle={backgroundColor:'#1bbd7e'}
const btnstyle={margin:'8px 0'}
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
var now = new Date();
function validateForm() {
return email.length > 0 && password.length > 0;
}
function goHome () {
window.location.assign("/Home");
}
function goReset () {
window.location.assign("/UpdatePassword");
}
function handleSubmit(event) {
Api.noToken().post('/users/login', {
email: email,
password: password,
resetDate: Math.floor(((now / 8.64e7) - 150.604166666))
})
.then(function (response) {
if(response.status === 204){//this means a password reset still needs to occur here
Api.withToken().get('/breaches/')
.then(res => {
breachesCallback(res.data);
console.log(res.data);
}).then(goReset());
}
else if(response.status === 200){
window.sessionStorage.setItem("token", response.data.token);
Api.withToken().get('/breaches/')
.then(res => {
breachesCallback(res.data);
console.log(res.data);
}).then(goHome());
}
})
.catch(function (error) {
alert("Invalid username or password")
});
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<Grid>
<Paper elevation={10} style={paperStyle}>
<Grid align='center'>
<Avatar style={avatarStyle}><LockIcon/></Avatar>
<h2>Sign In</h2>
</Grid>
<TextField label='Username' placeholder='Enter username' fullWidth required onChange={e => setEmail(e.target.value)}/>
<TextField label='Password' placeholder='Enter password' type='password' fullWidth required onChange={e => setPassword(e.target.value)}/>
<FormControlLabel
control={
<Checkbox
name="checkedB"
color="primary"
/>
}
label="Remember me"
/>
<Button type='submit' disabled={!validateForm()} color='primary' variant="contained" style={btnstyle} fullWidth>Sign in</Button>
<Typography >
<Link to="#" >
Forgot password ?
</Link>
</Typography>
<Typography > Do you have an account ?
<Link to="/AddAccount" >
Sign Up
</Link>
</Typography>
</Paper>
</Grid>
</form>
)
}

After hours of looking I've finally found the most up to date tool you are meant to use for react router in the latest update (currently 6.1.1)
This is about 3 posts down in this post (the other answers are all for older versions of react router and will not work)
The answer is simple:
import { useNavigate } from "react-router-dom";
then in your function add a simpler variable for useNavigate:
let navigate = useNavigate();
and replace your window.location.assign("/Home") with navigate("/Home", { replace: true });
(obviously could also just say useNavigate("/Home", {replace:true})

Related

Attempted import error: 'signInUserWithEmailAndPassword' is not exported from 'firebase/auth'

please i need your help
I'm using Firebase 9.02 and i'm facing a problem when i try to import signInUserWithEmailAndPassword to sign in my users with Firebase authentication module
Is it a problem in the version 9 of Firebase ?
Thank you in advance
import React, { useRef } from "react";
import "./SignUpScreen.css";
import auth from "../firebase";
import {
createUserWithEmailAndPassword,
signInUserWithEmailAndPassword,
} from "firebase/auth";
// import auth from "../firebase";
const SignUpScreen = () => {
const emailRef = useRef(null);
const passwordRef = useRef(null);
const signIn = (e) => {
e.preventDefault();
signInUserWithEmailAndPassword(auth, emailRef, passwordRef)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
alert(error);
});
};
return (
<div className='signupScreen'>
<form>
<h1>Sign In</h1>
<input
ref={emailRef}
className='signin'
type='email'
placeholder='Email'
/>
<input
ref={passwordRef}
className='signin'
type='password'
placeholder='Password'
/>
<button onClick={signIn} className='signin' type='submit'>
Sign In
</button>
</form>
</div>
);
};
export default SignUpScreen;```
No, the error is not a problem with version 9 of the Firebase SDK.
The issue is that the method is wrongly spelt.
It's signInWithEmailAndPassword and not signInUserWithEmailAndPassword.
Checkout the documentation

react-router 4 - Browser history needs a DOM

I am trying server side rendering using react-router 4. I am following the example provided here https://reacttraining.com/react-router/web/guides/server-rendering/putting-it-all-together
As per the example on server we should use StaticRouter. When I import as per the example I am seeing StaticRouter as undefined
import {StaticRouter} from 'react-router';
After doing some research online I found I could use react-router-dom. Now my import statement looks like this.
import {StaticRouter} from 'react-router-dom';
However when I run the code I am getting Invariant Violation: Browser history needs a DOM in the browser.
my server.js file code
....
app.get( '*', ( req, res ) => {
const html = fs.readFileSync(path.resolve(__dirname, '../index.html')).toString();
const context = {};
const markup = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context} >
<App/>
</StaticRouter>
);
if (context.url) {
res.writeHead(302, {
Location: context.url
})
res.end();
} else {
res.send(html.replace('$react', markup));
}
} );
....
And my client/index.js code
....
ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), root);
....
Update v1
Reduced my example to a bear minimum and still getting the same error.
clientIndex.js
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from '../App'
ReactDOM.render((
<BrowserRouter>
<App/>
</BrowserRouter>
), document.getElementById('app'))
serverIndex.js
import { createServer } from 'http'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router'
import App from '../App'
createServer((req, res) => {
const context = {}
const html = ReactDOMServer.renderToString(
<StaticRouter
location={req.url}
context={context}
>
<App/>
</StaticRouter>
)
res.write(`
<!doctype html>
<div id="app">${html}</div>
`)
res.end()
}).listen(3000);
App.js
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import routes from "./client/routes";
const App = ( ) => (
<Router>
<Route path="/" exact render={( props ) => ( <div>Helloworld</div> )} />
</Router>
)
export default App;
You need to use different history provider for server side rendering because you don't have a real DOM (and browser's history) on server. So replacing BrowserRouter with Router and an alternate history provider in your app.js can resolve the issue. Also you don't have to use two wrappers. You are using BrowserRouter twice, in app.js as well as clientIndex.js which is unnecessary.
import { Route, Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
const history = createMemoryHistory();
<Router history={history}>
<Route path="/" exact render={( props ) => ( <div>Helloworld</div> )} />
</Router>
You can now replace StaticRouter with ConnectedRouter which can be used both in client and server. I use the following code to choose between history and export it to be used in ConnectedRouter's history.
export default (url = '/') => {
// Create a history depending on the environment
const history = isServer
? createMemoryHistory({
initialEntries: [url]
})
: createBrowserHistory();
}
In clientIndex.js
Rather than BrowserRouter use StaticRouter.
import { BrowserRouter } from 'react-router-dom';
import { StaticRouter } from 'react-router-dom'
As is essentially noted in the comments, one may hit this error (as I have) by accidentally wrapping your App component in a <BrowserRouter>, when instead it is your client app that should be wrapped.
App.js
import React from 'react'
const App = () => <h1>Hello, World.</h1>
export default App
ClientApp.js
import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import ReactDOM from 'react-dom'
import App from './App'
const render = Component => {
ReactDOM.render(
<BrowserRouter>
<Component />
</BrowserRouter>,
document.getElementById('app')
)
}
render(App)
See also the React Router docs.

Server-side rendering(express) with react router does not work

I am trying server-side rendering using node js, React, Redux and React-Router.
I followed react-router server-side tutorial but I am only getting root route, no matter what route I put. As you see in the routes.js, I have a route to detail.
I tried path="detail" as well
and Link is like below
<Link to="/detail"> Detail</Link>
When I click that link, it does not even give me error like "no matched route to /detail".
If you want to see all codes - git repo
Here is my code
routes.js
export default ([
<Route path="/" component={App}>
<Route path="/detail" component={DetailView}/>
</Route>
]);
server.js
app.get('/*',(req,res)=>{
match({ routes:routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message)
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
const store = createStore(Reducers);
const html = renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
);
res.status(200).send(renderFullPage(html, store));
} else {
res.status(404).send('Not found')
}
})
});
renderFullPage - this basically injects html from rederToString to html string
<div id="app">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)}
</script>
client.js(index.js)
const history =createBrowserHistory();
match({ history, routes }, (error, redirectLocation, renderProps) => {
ReactDom.render(
<Provider store={store} >
<Router {...renderProps} />
</Provider> , document.getElementById('app'))
});
App.js
class App extends React.Component {
render() {
return (
<div>
<div className="container">
<PokemonContainer />
</div>
</div >
)
};
}
Thank you for look into it and please give me any opinion about this.
Try removing the leading slash:
export default ([
<Route path="/" component={App}>
<Route path="detail" component={DetailView}/>
</Route>
]);
No sure if that's the issue with routing but you have to pass store state to renderFullPage not the store itself. So it should be something like this:
} else if (renderProps) {
const store = createStore(Reducers);
const initialState = store.getState()
const html = renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
);
res.status(200).send(renderFullPage(html, initialState));
}

Meteor authentication and react-router

How do I get meteor to re-render my components when I sign in using the accounts-password package?
My react-router routes are:
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { Router, Route, IndexRoute, browserHistory } from 'react-router'
import App from './containers/App'
import Recordings from './containers/Recordings'
import LandingPage from './containers/LandingPage'
import { BloodPressure } from '../collections/BloodPressure'
const routes = (
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={LandingPage} />
<Route path="dashboard" component={Recordings} />
</Route>
</Router>
)
Meteor.startup( ()=> {
ReactDOM.render(routes, document.querySelector('.render-target'))
})
My App component is:
import React, { Component } from 'react'
import { createContainer } from 'meteor/react-meteor-data'
import { browserHistory } from 'react-router'
import Header from './Header'
class App extends Component {
constructor(props) {
super(props)
}
render() {
return(
<div>
<div className="ui four container">
<Header />
{this.props.children}
</div>
<div className="footer">
<p>Designed and Developed by Thomas Hoadley</p>
</div>
</div>
)
}
}
export default createContainer(() => {
return {
signedIn: Meteor.userId()
}
}, App)
When I sign in, I expect the page to automatically reload with the correct routes, however I am having to reload the page manually to redirect it.
Any help on this issue would be greatly appreciated!

React Router reports 404 Not Found when refresh

say, I have 2 pages, localhost and localhost/test, there's a link on localhost, which is to localhost/test.
localhost/test can be accessed via clicking the link, but when refreshing or input url localhost/test manually, it returns
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
My code is like this:
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, IndexRoute, Link, IndexLink, browserHistory } from 'react-router';
import session from 'express-session';
import $ from 'jquery';
const App = React.createClass ({
render() {
return (
<div>
Router lza.
<ul>
<li><Link to="test">Test</Link></li>
</ul>
</div>
);
}
})
const App2 = React.createClass ({
render() {
return (<div>Router lza.aasss</div>);
}
})
var routes = (
<Router history={browserHistory}>
<Route path="/">
<IndexRoute component={App} />
<Route path="/test" component={App2} />
</Route>
</Router>
)
ReactDOM.render(routes, document.getElementById("hello"))
How can it be solved?
I tried to solve it by express 4, but when I import express from 'express', it reports
Uncaught TypeError: Cannot read property 'prototype' of undefined
Thus I tried express-session, but I can't find a complete example of how to use it. Many examples has a var called 'app', but how it's defined? Or please just tell me how to make url can be accessed when refreshing. Thank you.