React Router - Cannot GET - express

I have created simple web application running on a MERN stack, I have just tried to set up my routing with react-router. Now I know this question has been asked before but answers were suggesting adding options to Webpack whereas I am using Browserify / Gulp.
My problem is that my all my routes except for root are returning with CANNOT get.
var Router = require('react-router').Router;
var Route = require('react-router').Route;
var Redirect = require('react-router').Redirect;
var browserHistory = require('react-router').browserHistory;
class Routes extends React.Component {
render() {
return (
<Router history={browserHistory}>
<Route path="/bugs" component={BugList} />
<Redirect from="/" to="/bugs"/>
<Route path="*" component={NotFound} />
</Router>
);
}
}

Firstly, I believe you need to import the components you're routing to. So for example:
var BugList = require('./components/bugList');
Also, I think you can remove the slashes except for the root route. So this should work:
<Route path="bugs" component={BugList} />

Related

React-Admin: How to redirect to <Dashboard> when authenticated through custom <Login> page

react-admin loads the <Dashboard> at the base "/". And for that reason, the custom page never opens by default because the <Admin> always routes to the dashboard.
I've implemented <PrivateRoutes> to handle authentication and it's a success.The <Login> page is loaded by default, and upon authentication, it routes to dashboard.
Challenge: This process breaks the functionality of Sidebar <links>, like "Users".
// CustomRoutes.js
export default [
<Route exact path="/login" component={LoginPage} noLayout />,
<Route exact path="/forgot-password" component={ForgotPassword} noLayout />,
<Route exact path="/confirm-password" component={ConfirmForgotPassword} noLayout />,
<PrivateRoute path="/" loggedIn={localStorage.getItem("access_token")} component={dashboard} />
];
And then...
// PrivateRoute.js
import React from "react";
import { Redirect, Route } from "react-router-dom";
const PrivateRoute = ({ path, component: Component, ...rest }) => {
const isLoggedIn = localStorage.getItem("access_token");
return (
<Route
path={path}
{...rest}
render={props => isLoggedIn
? <Component {...props} />
: <Redirect to={{ pathname: "/login", state: { from: props.location } }} />
}
/>
);
};
export default PrivateRoute;
Here's how it looks within the main <App>
// App.js
const App = () => (
<Admin
theme={myTheme}
dashboard={dashboard}
authProvider={authProvider}
dataProvider={dataProvider}
customRoutes={customRoutes}
loginPage={LoginPage}
logoutButton={LogoutButton}
forgotPassword={ForgotPassword}
>
<Resource name="users" list={UserList} create={UserCreate} show={UserShow} icon={UserIcon} />
</Admin>
);
export default App;
Please note that the <resource> "users" is not working.
Do I need to add custom route for that too?
Alright, let's debug this step-by-step:
We can take advantage of react-admin directly to handle the authentication via the authProvider.
Once you include the authProvider, react-adminenables a new page on the /login
route, which displays a <Login> form asking for username and password.
You can definitely customize that login page (as I assume you did),
and I advise that you avoid using a <PrivateRoute> since the authProvider redirects all users who aren't yet authenticated to /login.
Kindly note that <Admin> creates an application with its own state, routing, and controller logic.In your code, you added forgotPassword which is not a prop accepted by <Admin.
<admin
// remove this...
- forgotPassword={ForgotPassword}
>
I wonder exactly what error you get in this case, but this is the main bug.

Using React BrowserRouter (v4) how do I recognize when the location has changed?

Have the following JSX
// Root.jsx
<BrowserRouter getUserConfirmation={this.handleLocationChange}>
<Switch>
<Route path='/' exact component={Search} />
<Route path='/queue/' component={Queue} />
<Route path='/healthCheck/' component={HealthCheck} />
<Route path='/transcript' component={Transcript} />
</Switch>
</BrowserRouter>
// Root.js
export class Root extends Component{
constructor(props){
super(props);
}
handleLocationChange(message, callback) {
// your staff here
console.log(`- - - location:`);
callback(true);
}
render(){
return RootTemplate.call(this);
}
}
But when I run this I get...
Root.jsx:25 Uncaught TypeError: Cannot read property 'handleLocationChange' of undefined
at RootTemplate (Root.jsx:25)
at Root.render (Root.js:13)
If I try this...
getUserConfirmation={()=>this.handleLocationChange()}
I don't get an error but I also don't get my console like I would expect.
How do I tell when the location has changed?
Update
I also tried this just for testing...
const getConfirmation = (message, callback) => {
console.log("Welp this is working");
callback(true)
};
...
<BrowserRouter getUserConfirmation={getConfirmation}>
But still not seeing anything in the log.
If your trying to check when a user has navigated from one location in your app to another you should use the history library. You can also use it for getUserConfirmation, which is when a user navigates away from your application.
import createHistory from "history/createBrowserHistory";
import { Router } from "react-router";
// Fires when user navigates away
const getUserConfirmation = () => console.log("User navigated away");
// Create your browser history
const history = createHistory({getUserConfirmation});
// Fires every time a location is updated
history.listen((location) => console.log("Navigated to page", location));
// Attach your browser history to your router
const MyRouter = () => <Router history={history> {your children} </Router>
Use Prompt component from react-router. Include in one of you components.
Try doing this without using getUserConfirmation.
Prompt- https://reacttraining.com/react-router/core/api/Prompt

I am not able to set a specefic path in test

Problem: My App component is responsible to render the other components based on the path. So inorder to test it, I need to be able to "set" the path. e.g I'd like to see the SignUp component is rendered when the path is /sign-up.
What I've done: I thought I could use initialEntries to give the MemoryRouter an initial path (unsuccessful) then I thought I might be able to use Route/Redirect directly in my test inside MemoryRouter to set the path, but that did not work either.
Specification:
React 15
React Router 4 (react-router-dom)
Redux 3.6
Jest (the one comes with create-react-app)
Yo can find the code on the branch with the issue
I spent a while trying to figure this out myself.
Simply put you cannot nest a <Router> within the <MemoryRouter> as they are both Routers.
Solution Example:
Routes.js - Remove <BrowserRouter> from this so you can test your code.
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import SignUp from '../SignUp/SignUp'; //your signup component
import Home from '../Home/Home'; //some other component for an example
const MyRoutes = () => (
<Switch>
<Route path="/" component={Home} />
<Route path="/signup" component={SignUp} />
</Switch>
);
export default MyRoutes;
index.js - Add <BrowserRouter> here as you will need to wrap a <Switch> in a <Router>.
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import Routes from './Components/Routes/Routes';
ReactDOM.render(
(
<BrowserRouter>
<Routes />
</BrowserRouter>
), document.getElementById('root')
);
tests/Routes.test.js - Now add the <MemoryRouter> in here for testing.
import React from 'react';
import ReactDOM from 'react-dom';
import { MemoryRouter } from 'react-router-dom';
import Routes from '../Components/Routes/Routes';
const TestRoute = props => (
<MemoryRouter initialEntries={props.initialEntries}>
<Routes {...props} />
</MemoryRouter>
);
it('at /signup it displays the signup page', () => {
const div = document.createElement('div');
ReactDOM.render(<TestRoute initialEntries={['/signup']} />, div); // render on the route "/signup"
const elem = div.getElementsByClassName('signup')[0];
expect(elem).not.toBe(undefined); // check an element exists with that class
if(elem !== undefined) {
expect(elem.innerHTML).toEqual('signup'); // check it has worked
}
});
In other words you are separating the Routes/Switch from the Router to enable you to be able to test it, as you cannot nest two Routers.
I'm having a similar issue, I have found that the following works for testing components whose behaviour changes based upon the route:
<MemoryRouter initialEntries={['/about']}>
<Navigation {...props} />
</MemoryRouter>
In this instance, the snapshot shows that an .active className is added to the 'about' link in Navigation.
What does not seem to work is adding memory router around the component/container holding the initial routes. To keep things simple I have reduced my basic routing page to this:
<Router>
<div className="App">
<Navigation app={this.props.app} />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/about" component={About} />
<Route exact path="/login" render={() => <Login app={this.props.app} />} />
<Route exact path="/signup" render={() => <Signup app={this.props.app} />} />
<Route exact path="/account" render={() => <Account app={this.props.app} />} />
<Route component={ErrorPage} />
</Switch>
</div>
</Router>
The react-router team states in current testing docs:
We have a lot of tests that the routes work when the location changes,
so you probably don’t need to test this stuff.

React nested route not mounting

I want my routes to look like:
/
/signin
/discussion/:title
However, anything past the second forward slash causes an error, and all of my client-side dependencies are throwing Unexpected token errors. For instance, reactjs, my CSS, nor my image files are being loaded in my index.html file. I'm using ExpressJS on the backend. I use the following line on my server to push the routing to the client:
app.get('*', function(req, res, next) {
res.sendFile(path.join(__dirname, 'app/index.html'));
});
routes.jsx
var React = require('react'),
Router = require('react-router'),
Route = Router.Route,
IndexRoute = Router.IndexRoute,
App = require('./components/app/app.jsx'),
Home = require('./components/pages/home.jsx'),
Discussion = require('./components/pages/discussion.jsx'),
DiscussionArea = require('./components/pages/discussionArea.jsx'),
Signin = require('./components/pages/signin.jsx'),
NotFound = require('./components/pages/notFound.jsx');
var routes = (
<Route path='/' component={App}>
<IndexRoute component={Home} />
<Route path='discussion' component={Discussion}>
<Route path='/discussion/area' component={DiscussionArea} />
</Route>
<Route path='signin' component={Signin} />
<Route path='*' component={NotFound} />
</Route>
);
module.exports = routes;
main.jsx
var React = require('react'),
ReactDOM = require('react-dom'),
ReactRouter = require('react-router'),
Router = ReactRouter.Router,
routes = require('./routes.jsx'),
createHistory = require('history').createHistory;
ReactDOM.render((
<Router history={ createHistory() }>
{routes}
</Router>
), document.getElementById('app'));
Why are my nested routes not mounting using react-router?
I found the answer. Refer to this Stackoverflow answer: Minimum nodejs server setup needed for React using react-router and browserHistory
It has something to do with the way my server is serving the paths. My resources are being loaded relative to the URL, when they should be loading from the root of the server.
The solution was to add <base href="/"> to the head of my index.html file.

Routes with react-router 1.0.0-rc1, express, web pack

I am fairly new to react and express, so sorry for the newb questions.
In react-router v013.3, I used the below config and "this.context.router.transitionTo(payload.route);" to switch routes, and it worked fine.
However, in react-router v1.0.0-rc1, I've tried both "this.props.history.pushState(null, payload.route);" as well as "replaceState", but they don't render my route.
I cannot use the class since I have to switch routes programmatically.
This suggests that I add some code to my express config (please see below): https://github.com/rackt/react-router/blob/master/docs/guides/basics/Histories.md#createbrowserhistory
I also added 'historyApiFallback: true' to my webpack dev server config.
Although via console.log message I see history is receiving the route change request, my requested routes do not render.
Can anyone see what I'm missing?
Thanks!!!
// react-router v013.3
const AppRoutes = (
<Route path="/" handler={App}>
<DefaultRoute handler={Home} />
<Route name="myFieldMapping" handler={MyFieldMapping} />
<Route name="myValidation" handler={MyValidation} />
</Route>
);
Router.run(AppRoutes, Router.HashLocation, (Root) => {
React.render(<Root />, document.getElementById('content'));
});
// react-router v1.0.0-rc1
const myHistory = useBasename(createHistory)({
basename: '/myApp'
});
let unlisten = myHistory.listen(function (location) {
console.log('---...--- CALL TO history: ', location.pathname)
});
React.render((
<Router history={myHistory}>
<Route path="/" component={App} >
<IndexRoute component={Home} />
<Route path="myFieldMapping" component={MyFieldMapping} />
<Route path="myValidation" component={MyValidation} />
</Route>
</Router>
), document.getElementById('content'));
// express config
app.get('/myApp/*', function(request, response){
response.sendFile(path.resolve(__dirname, publicPath, 'index.html'))
});