React-Router Navigating Through Routes Using jQuery - javascript

Ok, I have my React-Router working more or less the way I want it but my issue is this: I now need to add a bit of functionality in my JS.
Example: The user enters their details and clicks 'login', I would like my jQuery to check if the credentials are correct and if they are change the route to the home page.
I have no idea, how I would go about this.
This is my React-Router code:
import React from 'react'
import ReactDOM from 'react-dom';
import { Router, Route, hashHistory, Navigation } from 'react-router'
import Login from './login'
import Signup from './signup'
import Home from './home'
ReactDOM.render((
<Router history={hashHistory}>
<Route path="/" component={Login}/>
<Route path="/signup" component={Signup}/>
<Route path="/home" component={Home}/>
</Router>
), document.getElementById("app"))
$("#loginBtn").click(
function(){
var email = $('loginEmail').val();
var pass = $('loginpwd').val();
/* Check to see if credential are correct.
* If so, change to '/home route
*/
}
);
Any ideas would be greatly appreciated. Thanks :)

One way would be the following:
const openAppRoute = (route) => {
// Summary:
// Helper function for developers to navigation
// to a different route programmatically.
hashHistory.push(route);
};
window.openAppRoute = openAppRoute;
$("#loginBtn").click(
function(){
var email = $('loginEmail').val();
var pass = $('loginpwd').val();
/* Check to see if credential are correct.
* If so, change to '/home route
*/
window.openAppRoute("/home");
}
);

Related

Reactjs how to add variable in URL parameter

The link from my backend produce ?id= for my frontend to parse using queryString. Is there a way to get this link to load in the frontend?
http://localhost:3000/resetpassword/?id=61bc1fbe3490be4f3594cc3e/?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI2MWJjMWZiZTM0OTBiZTRmMzU5NGNjM2UiLCJmaXJzdG5hbWUiOiJPY2VhbiIsImxhc3RuYW1lIjoiUnlhbiIsImVtYWlsIjoib2NlYW5yeWFuNzI1QHlhaG9vLmNvbSIsInBob25lTnVtYmVyIjo2MjgxMTYxNTIyNjMyLCJkb2IiOiIyMDAwLTA3LTI1VDAwOjAwOjAwLjAwMFoiLCJwYXNzd29yZCI6IiQyYiQxMCR6Li9hMHFQYVFzdnNCUEtxc2QuaENlWmI3OWpIYW1VdHdXNmVnSEpLLlhndHFGZzV3djJ0bSIsIl9fdiI6MH0.21irj8fCPQFvCqmp-3E9BJmqwVp81gyQxIW5LgFplMg
App.js
import './App.css';
import { BrowserRouter,
Routes,
Route,
} from "react-router-dom"; //v6
import LandingPage from "./pages/LandingPage/LandingPage";
import ResetPwPage from "./pages/ResetPwPage/ResetPw";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<LandingPage/>}/>
<Route path="/resetpassword/:id/:token" element={<ResetPwPage/>} />
</Routes>
</BrowserRouter>
);
}
export default App;
I tried
<Route path="/resetpassword/?id=:id/?token=:token" element={<ResetPwPage/>} />
But it doesnt work.
I need the link to contain ?id= and ?token= since i need to get the value of id and token in the frontend as required with queryString.
const parsed = queryString.parse(location.search);
console.log(parsed);
//=> {foo: 'bar'}
Any suggestion or alternatives is much appreciated. Thank you!
In react-router-dom the router and routes/paths don't concern themselves with the queryString, they only care about the path part of the URL. In RRDv6 there is a new useSearchParams hook for accessing and reading from the queryString.
path
/resetpassword/?id=61bc1fbe3490be4f3594cc3e&token=eyJ0eX.....
Remove the bits from the path that was trying to read the queryString.
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<LandingPage/>} />
<Route path="/resetpassword" element={<ResetPwPage/>} />
</Routes>
</BrowserRouter>
);
}
ResetPwPage
import { useSearchParams } from 'react-router-dom';
...
const [searchParams] = useSearchParams();
...
const id = searchParams.get("id");
const token = searchParams.get("token");

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 to integrate dynamic routes in Docusaurus with react-router

I have a website made with Docusaurus v2 that currently contains documentation. However, I would like to add a page of a list of workflows where if a workflow in the list is clicked, the user would be shown a page of additional details of that workflow. For now it seems docusaurus.config seems to be handling most of the routing, but is there a way I can add a dynamic route like /workflows/:id? I made a separate standalone app which had a Router object and it worked if my App.js looks like this:
// App.js
import Navigation from './Navigation'
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
function App() {
return (
<Router>
<Navigation />
<Switch>
<Route path="/" exact component={Home}></Route>
<Route path="/workflows" exact component={Workflows}></Route>
<Route path="/workflows/:id" component={WorkflowItem}></Route>
</Switch>
</Router>
)
}
Is it possible to add the Router somewhere in Docusaurus?
Thanks!
I solved this by creating a simple plugin to add my own custom routes. Documentation here.
Let's call the plugin plugin-dynamic-routes.
// {SITE_ROOT_DIR}/plugin-dynamic-routes/index.js
module.exports = function (context, options) {
return {
name: 'plugin-dynamic-routes',
async contentLoaded({ content, actions }) {
const { routes } = options
const { addRoute } = actions
routes.map(route => addRoute(route))
}
}
}
// docusaurus.config.js
const path = require('path')
module.exports = {
// ...
plugins: [
[
path.resolve(__dirname, 'plugin-dynamic-routes'),
{ // this is the options object passed to the plugin
routes: [
{ // using Route schema from react-router
path: '/workflows',
exact: false, // this is needed for sub-routes to match!
component: '#site/path/to/component/App'
}
]
}
],
],
}
You may be able to use the above method to configure sub-routes as well but I haven't tried it. For the custom page, all you need is the Switch component (you are technically using nested routes at this point). The Layout component is there to integrate the page into the rest of the Docusaurus site.
// App.js
import React from 'react'
import Layout from '#theme/Layout'
import { Switch, Route, useRouteMatch } from '#docusaurus/router'
function App() {
let match = useRouteMatch()
return (
<Layout title="Page Title">
<Switch>
<Route path={`${match.path}/:id`} component={WorkflowItem} />
<Route path={match.path} component={Workflows} />
</Switch>
</Layout>
)
}

React router scrolls new page down

I came across an issue using react-router ^2.4.1 where if I scroll down on my home page and afterwards go to a new page it will also be scrolled down, as opposed to being at the top (expected behaviour).
I am using this starter pack: react-webpack-node and my routes.jsx looks like this
import React from 'react'
import { Route, IndexRoute } from 'react-router'
import cookie from 'react-cookie'
import App from 'containers/App'
import HomePage from 'containers/HomePage'
import WaitingListPage from 'containers/WaitingListPage'
import NotFoundPage from 'containers/NotFoundPage'
import SupportPage from 'containers/SupportPage'
/*
* #param {Redux Store}
* We require store as an argument here because we wish to get
* state from the store after it has been authenticated.
*/
export default (store) => {
const hasQueueToken = (nextState, replace, callback) => {
if (cookie.load('queueToken')) {
replace({
pathname: `/waiting-list/${cookie.load('queueToken')}`,
state: { nextPathname: nextState.location.pathname }
})
}
callback()
}
return (
<Route path='/' component={App}>
<IndexRoute component={HomePage} />
<Route path='/w_ref/:ref' component={HomePage} />
<Route path='/waiting-list/:token' component={WaitingListPage} />
<Route path='/waiting-list' onEnter={hasQueueToken} component={WaitingListPage} />
<Route path='/support' component={SupportPage} />
<Route path='/terms-and-conditions' component={TermsConditions} />
<Route path='/privacy-policy' component={PrivacyPolicy} />
<Route path='*' component={NotFoundPage} />
</Route>
)
}
React Router does not include scroll state management starting in version 2.0.0.
The recommended approach is to decorate the router with scroll-behavior using react-router-scroll as seen in this example:
import { applyRouterMiddleware, browserHistory, Router } from 'react-router';
import useScroll from 'react-router-scroll';
/* ... */
ReactDOM.render(
<Router
history={browserHistory}
routes={routes}
render={applyRouterMiddleware(useScroll())}
/>,
container
);
#John Trichereau:
scrolling to bottom can be done by giving a callback to useScroll, your callback would look like:
function customScroll (prevRouterProps, location) {
// on route /foo scroll to bottom
if (location.pathname == '/foo') return 'fooBottomDiv';
// on all other routes, follow useScroll default behavior
return prevRouterProps && location.pathname !== prevRouterProps.location.pathname;
}
and you would pass it to your router like this:
<Router render={ applyRouterMiddleware(useScroll((prevRouterProps, { location }) => customScroll(prevRouterProps, location))) }>
In your page, you would need to insert an invisible div with id fooBottomDiv. If you don't want to insert such a div, then you can have customScroll return a 2-element array [x, y] which could be [0, Number.MAX_SAFE_INTEGER] to scroll to bottom.
Documentation here
Note however that if your page has a component which loads data and displays it, it will most likely not work as the customScroll function is only called upon route matching, whereas your data is probably called asynchronously and received after route matching.
In this case, it's most convenient to use
ReactDOM.findDOMNode(this.refs.fooBottomDiv).scrollIntoView({ behavior: 'smooth' });
in React lifecycle methods componentDidMount and componentDidUpdate, where your component would contain an empty div with ref attribute ref='fooBottomDiv.

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