Heroku is giving me 404 error, only renders "Unkown path"? - javascript

I'm trying to deploy my application to heroku, however when I try to open the link to it, the only thing being rendered is "unkown path", erros being "Failed to load resource: the server responded with a status of 404 (Not Found)".
I kept checking the routes files as much as I could and I can't see what doesn't work here. This is how the index.js file looks like
import route from './router.js';
import Login from '../ui/pages/user/Login';
import Home from '../ui/Home';
import Register from '../ui/pages/user/Register';
import PostCreate from '../ui/pages/post/PostCreate';
import PostList from '../ui/pages/post/PostList';
import PostEdit from '../ui/pages/post/PostEdit';
route('/', Home, {}, {
name: 'home'
});
route('/login', Login, {}, {
name: 'login'
});
route('/register', Register, {}, {
name: 'register'
});
route('/post/create', PostCreate, {}, {
name: 'post.create'
});
route('/post/list', PostList, {}, {
name: 'post.list'
});
route('/post/edit/:_id', PostEdit, {}, {
name:'post.edit'
});
And this is the router.js file
import { createRouter } from 'meteor/cultofcoders:meteor-react-routing';
import App from '/imports/ui/App.jsx';
export default createRouter(App);
Could it just be an issue regarding the routing package I'm using?

I feel you are using the "wrong" router. cultofcoders:meteor-react-routing seems to not have been maintained in the past 2 years which is huge in terms of react routing. Would you be interested to try "react-router": "^5.0.0" with "react-router-dom": "^5.0.0" then you have something like:
import React from 'react'
import { Switch, Route, Redirect } from 'react-router-dom'
import Component1 from '.....'
import Component2 from '.....'
const Main = location => {
return (
<Switch location={location.location}>
<Route exact path='/' component={Component1} />
<Route exact path='/something' component={Component2} />
<Route exact path='/something/:id' component={Component2} /> // route with param
<Route path='*' component={NotFoundPage} />
...........
</Switch>)
}

Related

How do you use react-router-dom to redirect user when token has expired?

I have a React application that accesses a Flask API. To access some API routes, the user needs to log in. I am using Axios to do the requests. Then, he receives a token which is stored in the local storage. When this token expires and the user makes another request, I want to redirect him to the login page. However, I don't know how I would do it.
I am treating API request errors with Axios response interceptor. It removes the token from the local storage and then should redirect the user to the login page. Since I am using functional components, I could not find an example that fits well (besides downloading another package called history).
I have tried to use the 'useHistory' hook and Redirect from react-router-dom (with a proper BrowserRouter set up), but it doesn't work.
api.js
import axios from "axios"
import { RemoveAuth } from "./Auth"
export const api = axios.create({
baseURL: "http://localhost:5000/api/",
timeout: 15000,
})
// more code
api.interceptors.response.use(null, (error) => {
if(error.response.status === 401){
RemoveAuth();
}
return error;
});
Auth.js
import { useHistory } from "react-router-dom"
export const RemoveAuth = () => {
let history = useHistory()
localStorage.clear();
history.push('/login')
}
routes.js
import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import PrivateRoutes from "./PrivateRoutes";
import Dashboard from "../pages/dashboard";
import Login from "../pages/login";
import Logout from "../pages/logout";
const Routes = () => (
<BrowserRouter>
<Switch>
<PrivateRoutes exact path="/dashboard" component={Dashboard} />
<PrivateRoutes exact path="/logout" component={Logout} />
<Route exact path="/login" component={Login} />
</Switch>
</BrowserRouter>
);
PrivateRoutes.js
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { AuthLogin } from "../services/Auth";
const PrivateRoutes = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={() => (AuthLogin() ? <Redirect to="/login" /> : <Component />)}
/>
);
export default PrivateRoutes;
Thanks in advance for the help!
The simplest thing to do is to create your own history object. Something like this:
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
export default history;
Then in your provider pass in your custom history object:
import { Router } from 'react-router-dom'
import history from './utils/history'
ReactDOM.render(
<Router history={history}>
<App />
</Router>
document.getElementById('root')
);
This allows you to utilize your history in non-component code. Just import your history object into your Auth.js file and use it:
import { history } from './utils/history'
export const RemoveAuth = () => {
localStorage.clear();
history.push('/login')
}
As an added bonus, now your history lives in a place that is easily mock-able, so creating testing around it is more straightforward. You can find more information about creating your own custom history object in the docs.

MERN: react-router-dom <Redirect/> not working in Heroku

My app's routes are working fine. All the front-end routes you will see below render as intended.
However, if you go to the app and type /tournaments or /users it will display the raw json because those are two paths I defined in the backend Express routes for some of the data stuff.
So, I found a solution using Redirect via react-router-dom, and it works:
ValidateRoute.js
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
const ValidateRoute = props => {
if(props.type === "invalid") return <Redirect to="/" />;
else return <Route {...props} />
};
export default ValidateRoute;
App.js
import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css'
import './App.css';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import { Container, Row, Col } from 'reactstrap';
import { Provider } from 'react-redux';
import store from './store';
import NavigationBar from './components/layout/NavigationBar';
import ProfileSidebar from './components/layout/ProfileSidebar';
import TournamentIndex from './components/tournaments/Index';
import TournamentShow from './components/tournaments/Show';
import TournamentStart from './components/tournaments/Start';
import PlayerProfile from './components/players/PlayerProfile';
import PlayerDirectory from './components/players/PlayerDirectory';
import News from './components/news/SmashNews';
import { loadUser } from './actions/authActions';
import ValidateRoute from './components/ValidateRoute';
export default class App extends Component{
componentDidMount() {
store.dispatch(loadUser());
};
render() {
return (
<Provider store={store}>
<Router>
<NavigationBar />
<Container>
<Row className="justify-content-sm-center justify-content-md-center">
<Col sm="7" md="7" lg="5" xl="5">
<ProfileSidebar />
</Col>
<Col sm="7" md="7" lg="7" xl="7">
<Switch>
<Route exact path="/" component={TournamentIndex} />
<Route path="/tournaments/:id" component={TournamentShow} />
<Route path="/tournaments/:id/start" component={TournamentStart} />
<Route path="/players" component={PlayerDirectory} />
<Route path="/player/:id" component={PlayerProfile} />
<Route path="/smash-news" component={News} />
<ValidateRoute path="/tournaments" type="invalid"/>
<ValidateRoute path="/users" type="invalid"/>
</Switch>
</Col>
</Row>
</Container>
</Router>
</Provider>
);
};
};
With that, when I try /tournaments or /users, it redirects to main path "/" on localhost only.
On heroku however, it still just displays the backend json and no Redirect takes place.
I can't find any solution about this, only similar issues that don't exactly fit this scenario. Anyone got an insight? Thanks
Try to use this:
history.push(‘/‘)
Method by bringing history from react-router-dom
my answer is going to be a bit different than expected as this is going to be a change in the backend code and not in the frontend as you said that:
However, if you go to the app and type /tournaments or /users it will display the raw json because those are two paths I defined in the backend Express routes for some of the data stuff.
So I think what would be the best solution is not trying to use Redirect as a fix but rather put add /api/v1/[route name] to all of your routes, for example:
const express = require("express");
const router = express.Router();
// Import Routes
const usersRoute = require("./users");
const jobsRoute = require("./jobs");
const utilRoute = require("./utils");
const betsRoute = require("./bets");
// Routes
router.use("/api/v1/users", usersRoute);
router.use("/api/v1/jobs", jobsRoute);
router.use("/api/v1/utils", utilRoute);
router.use("/api/v1/bets", betsRoute);
Once you have done so, you could add a proxy on your frontend for each request that starts with /api/ it will proxy it to the server address based on production/development mode which when run locally will be localhost:PORT and production will be something else.
to proxy the request you would need the 'http-proxy-middleware' and it can be used as such:
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function (app) {
app.use(
'/api',
createProxyMiddleware({
target: `${process.env.REACT_APP_API_ENDPOINT}`,
changeOrigin: true,
}),
);
};
process.env.REACT_APP_API_ENDPOINT will be your api endpoint which you will store inside an env file. based on the NODE_ENV you could use different env files based on which script you run.
I know this is a long answer, but this will make your code much cleaner and no future issues will arise from using the same endpoints for the frontend or backend.

How can access browser history within react shepherd

I am trying to use React Shepherd to create a walkthrough for my application.
I can't seem to find anything that explains how to switch routes within the tour. window.location.replace = "/someurl" refreshes the page and kills the tour completely. I am trying to achieve something along the lines of this
History.js
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default history;
steps.js
import hist from "./History";
const Steps = [
{
//...
when: {
hide: () => {
hist.push("/someurl");
},
},
},
//...
]
export default Steps;
App.js
import React from "react";
import { Router } from "react-router";
import { Route } from "react-router-dom";
//...
import Steps from "./Steps";
import hist from "./History";
import "shepherd.js/dist/css/shepherd.css";
const tourOptions = {
defaultStepOptions: {
cancelIcon: {
enabled: true,
},
classes: "shepherd-theme-custom",
},
useModalOverlay: true,
};
const App = () => {
return (
<Router history={hist}>
<Route exact path="/signin" component={SignIn} />
<ShepherdTour steps={Steps} tourOptions={tourOptions}>
<PrivateRoute exact path="/*" component={Main} />
</ShepherdTour>
</Router>
);
};
export default App;
When the steps' hide function is called, the url path is switched but the page is not rendered. I am wondering if I am using react-router wrong or is there a different way to go about this?
So this actually had nothing to do with React Shepherd at all, this was purely a React Router issue. I mistakenly nested two BrowserRouter's since it was also accidentally included in my Main component. Once removed the application navigates with custom history file just fine.

React Router: Failed to Navigate Route

I setup simple route within my index.js file.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import reduxThunk from 'redux-thunk';
import '../less/app.less';
import reducers from './reducers';
import App from './components/App';
import Login from './components/auth/Login';
import Welcome from './components/Welcome';
// const defaultSetting = settings;
const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Welcome} />
<Route path="login" component={Login} />
</Route>
</Router>
</Provider>
, document.querySelector('.container')
);
my App.js
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
export default App;
When I navigate to localhost:8080 using webpack-dev-server I can properly show my index route. but when I navigate to localhost:8080/login' it shows errorCannot GET /login`.
Any solution?
By default the server will look for an html file at the /login route. So you should configure it for html5 navigation to return you index.html for any route it receives.
EDIT:
To do so in webpack, as you suggest in the comments, you can add this to your webpack dev server config:
historyApiFallback: true
index.html should be the default, so no need to specify it.
Also please note that urls containing dots are still pointing to files and thus redirected to the server. For example, if you have an url such as /search/firsname.lastname you would need to add a handler for this.
historyApiFallback: {
rewrites: [
{
from: /^\/search\/.*$/,
to: function() {
return 'index.html';
}
}
]
},
See this issue for more info.

React router - undefined history

I am trying to use the 1.0.0-rc1 react-router and history 2.0.0-rc1 to navigate manually through the website after pressing the button. Unfortunately, after pressing the button I get:
Cannot read property 'pushState' of undefined
My router code:
import React from 'react';
import { Router, Route, Link, browserHistory } from 'react-router'
import AppContainer from './components/AppContainer.jsx';
import MyTab from './components/test/MyTab.jsx';
import MainTab from './components/test/MainTab.jsx';
var routes = (
<Route component={AppContainer} >
<Route name="maintab" path="/" component={MainTab} />
<Route name="mytab" path="/mytab" component={MyTab} />
</Route>
);
React.render(<Router history={browserHistory}>{routes}</Router>, document.getElementById('main'));
The navigation button is on MyTab and it attemps to navigate to MainTab:
import React from 'react';
import 'datejs';
import History from "history";
export default React.createClass({
mixins: [ History ],
onChange(state) {
this.setState(state);
},
handleClick() {
this.history.pushState(null, `/`)
},
render() {
return (
<div className='container-fluid' >
<button type="button" onClick={this.handleClick.bind(this)}>TEST</button>
</div>
);
}
});
When I use history with this.props.history everything works fine. What is the problem with this code?
EDIT.
After adding the following:
const history = createBrowserHistory();
React.render(<Router history={history}>{routes}</Router>, document.getElementById('main'));
I try to access my app. Before (without history={history}), I just accessed localhost:8080/testapp and everything worked fine - my static resources are generated into dist/testapp directory. Now under this URL I get:
Location "/testapp/" did not match any resources
I tried to use the useBasename function in a following way:
import { useBasename } from 'history'
const history = useBasename(createBrowserHistory)({
basename: '/testapp'
});
React.render(<Router history={history}>{routes}</Router>, document.getElementById('main'));
and the application is back, but again I get the error
Cannot read property 'pushState' of undefined
in the call:
handleClick() {
this.history.pushState(null, `/mytab`)
},
I thougt it may be because of my connect task in gulp, so I have added history-api-fallback to configuration:
settings: {
root: './dist/',
host: 'localhost',
port: 8080,
livereload: {
port: 35929
},
middleware: function(connect, opt){
return [historyApiFallback({})];
}
}
But after adding middleware all I get after accessing a website is:
Cannot GET /
As of "react-router": "^4.1.1", you may try the following:
Use 'this.props.history.push('/new-route')'. Here's a detailed example
1: Index.js
import { BrowserRouter, Route, Switch } from 'react-router-dom';
//more imports here
ReactDOM.render(
<div>
<BrowserRouter>
<Switch>
<Route path='/login' component={LoginScreen} />
<Route path='/' component={WelcomeScreen} />
</Switch>
</BrowserRouter>
</div>, document.querySelector('.container'));
Above, we have used BrowserRouter, Route and Switch from 'react-router-dom'.
So whenever you add a component in the React Router 'Route', that is,
<Route path='/login' component={LoginScreen} />
..then 'React Router' will add a new property named 'history' to this component (LoginScreen, in this case). You can use this history prop to programatically navigate to other rountes.
So now in the LoginScreen component you can navigate like this:
2: LoginScreen:
return (
<div>
<h1> Login </h1>
<form onSubmit={this.formSubmit.bind(this)} >
//your form here
</form>
</div>
);
formSubmit(values) {
// some form handling action
this.props.history.push('/'); //navigating to Welcome Screen
}
Because everything changes like hell in react world here's a version which worked for me at December 2016:
import React from 'react'
import { Router, ReactRouter, Route, IndexRoute, browserHistory } from 'react-router';
var Main = require('../components/Main');
var Home = require('../components/Home');
var Dialogs = require('../components/Dialogs');
var routes = (
<Router history={browserHistory}>
<Route path='/' component={Main}>
<IndexRoute component={Home} />
<Route path='/dialogs' component={Dialogs} />
</Route>
</Router>
);
module.exports = routes
To create browser history you now need to create it from the History package much like you've tried.
import createBrowserHistory from 'history/lib/createBrowserHistory';
and then pass it to the Router like so
<Router history={createBrowserHistory()}>
<Route />
</Router>
The docs explain this perfectly

Categories