How to navigate to a new page react router v4 - javascript

I'm building a crypto currency market app as an to practice reactjs. When app starts list of currencies with some properties will be shown as a list. I need to navigate to a different page (new page - Currency component) without loading the component on the bottom of current page. At the moment I was able to render it in the bottom of the page. But that's not what I need.
Is there any other way than which is mentioned in Route to different page[react-router v4] ? Because I need to pass the clicked object (currency) to the new component (Currency)
Here's my CryptoList component currency_main.js
import React, { Component } from 'react';
import {
Table,
TableBody,
TableHeader,
TableHeaderColumn,
TableRow,
TableRowColumn,
} from 'material-ui/Table';
import Currency from './currency';
import {
BrowserRouter as Router,
Link,
Route
} from 'react-router-dom'
class CryptoList extends Component {
constructor(props){
super(props);
this.state = {
currencyList : [],
showCheckboxes : false,
selected : [],
adjustForCheckbox : false
}
};
componentWillMount(){
fetch('/getcurrencylist',
{
headers: {
'Content-Type': 'application/json',
'Accept':'application/json'
},
method: "get",
dataType: 'json',
})
.then((res) => res.json())
.then((data) => {
var currencyList = [];
for(var i=0; i< data.length; i++){
var currency = data[i];
currencyList.push(currency);
}
console.log(currencyList);
this.setState({currencyList})
console.log(this.state.currencyList);
})
.catch(err => console.log(err))
}
render(){
return (
<Router>
<div>
<Table>
<TableHeader
displaySelectAll={this.state.showCheckboxes}
adjustForCheckbox={this.state.showCheckboxes}>
<TableRow>
<TableHeaderColumn>Rank</TableHeaderColumn>
<TableHeaderColumn>Coin</TableHeaderColumn>
<TableHeaderColumn>Price</TableHeaderColumn>
<TableHeaderColumn>Change</TableHeaderColumn>
</TableRow>
</TableHeader>
<TableBody displayRowCheckbox={this.state.showCheckboxes}>
{this.state.currencyList.map( currency => (
<TableRow key={currency.rank}>
<TableRowColumn>{currency.rank}</TableRowColumn>
<TableRowColumn><Link to='/currency'>{currency.name}</Link></TableRowColumn>
<TableRowColumn>{currency.price_btc}</TableRowColumn>
<TableRowColumn>{currency.percent_change_1h}</TableRowColumn>
</TableRow>
))}
</TableBody>
</Table>
<div>
<Route path='/currency' component={Currency} />
</div>
</div>
</Router>
);
}
}
export default CryptoList;
And here's my Currency component currency.js
import React, { Component } from 'react';
class Currency extends Component {
componentWillMount(){
console.log(this.props.params);
}
render(){
return (
<div>
<h3>
This is Currency Page !
</h3>
</div>
);
}
}
export default Currency;
And here's the currency component which I need to render into a new page when I click currency name in the currency_main component (Which is in second <TableRowColumn>).
I'm bit new to react and tried react-router in a tutorial only and it was rendering a page as a part of currenct page only.
So how can I go to a new page using react-router v4 ?
P.S : I've uploaded the image. As an example if click on Ethereum I need to render the Currency component as a new page.
And this should be resulted as the output when I click on Ethereum (as an example) instead of rendering This is Currency Page ! on the same component CryptoList.

You already had the imports in this.
import {
BrowserRouter as Router,
Link,
Route
} from 'react-router-dom'
However, I would remove all of the routings in your CyptoList page and just make that CyptoList a component.
Now, you want to use those Links in your code to navigate between pages you need to make a place that you want to display the links in.
const Header = () => (
<nav>
<ul>
<li><Link to='/'>CryptoList</Link></li>
<li><Link to='/currency'>Currency</Link></li>
</ul>
</nav>
)
If in your CyptoList page you can just put the header in there like this <Header />
Now, the next part, the Router, you might want to make a new Router.js file or separate it. Or you could do something like this.
// Routes.js
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import CryptoList from './CryptoList'; // or whatever the location is
import Currency from './Currency'; // or whatever the location is
export default () => (
<BrowserRouter>
<Switch>
<Route exact path="/" component={CryptoList}/>
<Route path="/currency" component={Currency}/>
</Switch>
</BrowserRouter>
);
Then when you want to include your Routes as you saved it in the Routes.js file you can just do this.
import Routes from './Routes';
and use it by doing this...
<Routes />
You can always refer to this example on medium with a link to a CodeSandbox and CodePen. https://medium.com/#pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf

I encountered the same problem.
Your <Route /> is located in App.js. This is why every time you navigate to currency component you can still see original view in App.js.
Here is the solution:
You just need to move <Route /> to index.js not in App.js. Because in index.js there is nothing. when you navigate to <Currency /> you will go to a completely new page. You will never see views in App.js

Related

How to stop reloading screen when go back to previous screen with dom-router in react js

I have a web app with multiple pages and routing, in every single page I have table with lots of data, so every time I change page and press back button, the history page is reloads itself.
I want to keep the data of ListingPage as it is when I goBack to ListingPage from DetailPage. But every time it calls getAllRecords function and reloads the table.
I tried changing dom options and components but still not getting a proper solution
My App page structure is something like as below
App.js
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import HomePage from './Pages/HomePage.js'
import ListingPage from './Pages/ListingPage.js'
import DetailPage from './Pages/DetailPage.js'
render() {
return (
<BrowserRouter>
<Switch>
<Route path="/home" component={HomePage} />
<Route path="/list" component={ListingPage} />
<Route path="/detail" component={DetailPage} />
</Switch>
</BrowserRouter>
)
}
HomePage.js
import React, { Component } from 'react';
class HomePage extends Component {
render() {
return (
<div>
//Showing list of different table and pages
</div>
);
}
}
export default HomePage;
ListingPage.js
import React, { Component } from 'react';
class ListingPage extends Component {
componentDidMount(){
this.getAllRecords()
}
getAllRecords = () => {}
goToDetailRecord = () => {
this.props.history.push('detail')
}
render() {
return (
<div>
//Table list data
</div>
);
}
}
export default ListingPage;
DetailPage.js
import React, { Component } from 'react';
class DetailPage extends Component {
goBack = () => {
this.props.history.goBack();
}
render() {
return (
<div>
//Shows table data detail value
</div>
);
}
}
export default DetailPage;
Is there anything I can implement to resolve the issue. Thanks in advance.
You can either useMemo or the react 16 and older version of that to store a cache to prevent it doing so on re renders or save the value in state using redux and not call the function if the field isn't empty. Also if component did mount works like useEffect I think by you having it there it will call that function on each re render.

How do I redirect using a relative URL?

I am trying to redirect a Sign Out button from a dropdown on my page. When I click on the sign out as of right now it will go to localhost:3000/signout. I have tried:
export const SIGNOUT="redirect=www.google.com";
and it will simply replace the URL as localhost:3000/redirect=www.google.com.
I have tried :
<Route exact path={SIGNOUT}>
<Redirect to={www.google.com}/>
</Route>
export const SIGNOUT="www.google.com";
This will redirect to google.com upon loading and won't even let me load my own webpage:
export const SIGNOUT= window.location.replace("http://www.google.com");
urlLists.js
export const SIGNOUT= "www.google.com";
App.js
import {SIGNOUT} from "./utils/urlLists";
class App extends Component {
render() {
const {location} = this.props
return (
<Switch>
<Route exact path={SIGNOUT}>
<Redirect to={HOME}/>
</Route>
</Switch>
);
}
}
export default withRouter(App);
I expect the results of this to redirect to Google upon clicking on the Sign Out dropdown option.
The actual result is either a redirection to:
localhost:3000/www.google.com
or the Google page is loaded and my localhost:3000 does not.
The idea is to redirect inside your Home component. Take a look at this sample implementation.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function Home() {
return (
<div className="App">
<h1>Hello World</h1>
<button
name="sign-out"
onClick={() => {
// sign user out here
window.location.assign("www.google.com");
}}
>
Sign Out
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Home />, rootElement);
The Redirect component is nice for redirecting to an internal route. However, if you're kicking the user out of your app you should use something else like window.location.assign().
Whatever included in the "" is the thing added to the domain. For example export const SIGNOUT= window.location.replace("google"); will become localhost:3000/google.
If you want to use "www.google.com", try to import it as a thing of its own at the beginning of the page, like "import Google from "www.google.com", then use the {Google} element.
You can try this:
import React from 'react'
import { Redirect } from 'react-router-dom'
const ProtectedComponent = () => {
if (authFails)
return <Redirect to='redirect=www.google.com' />
}
return <div> My Protected Component </div>
}

How to make material ui sidebar to open the main content in react?

I am a newbie to react and currently developing an application,
BACKGROUND
It has admin, faculty, student, dashboards.amd a static landing page with buttons to go to /admin/login ,/faculty/login ,/student/login. which opens respective dashboards [![Once admin logins he gets this dashboard page ][1]][1]
PROBLEM:
App.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import Routes from "./routes";
import firebase from "./Firebase";
const App = props => {
return (
<BrowserRouter>
<Routes {...props} />
</BrowserRouter>
);
};
firebase.auth().onAuthStateChanged(user => {
ReactDOM.render(<App user={user} />, document.getElementById("root"));
});
Routes.js
import React from "react";
import { Switch, Route, BrowserRouter } from "react-router-dom";
import MainLayout from "./OtherComponents/Common/MainLayout";
//Home
import Home from "./MainComponents/Home";
import HomePublicRoute from "./OtherComponents/Routes/Home/HomePublicRoute";
//ADMIN
//components
import AdminLogin from "./OtherComponents/Login/Admin";
import AdminDash from "./MainComponents/Admin";
import AdminPublicRoute from "./OtherComponents/Routes/Admin/AdminPublicRoutes";
import AdminPrivateRoute fro"./OtherComponents/Routes/Admin/AdminPrivateRoutes";
//pages
import PageDashboard from "./MainComponents/Admin/pages/dashboard";
import AdminTaluka from "./MainComponents/Admin/pages/taluka";
const Routes = props => {
console.log(props);
return (
<MainLayout>
<Switch>
<AdminPublicRoute
{...props}
exact
restricted={true}
path="/admin/login"
component={AdminLogin}
/>
<AdminPrivateRoute
{...props}
path="/admin/admindashboard"
exact
component={AdminDash}
/>
<AdminPrivateRoute
{...props}
path="/admin/pagedashboard"
exact
component={PageDashboard}
/>
<AdminPrivateRoute
{...props}
path="/admin/taluka"
exact
component={AdminTaluka}
/>
<HomePublicRoute path="/" component={Home} />
</Switch>
</MainLayout>
);
};
export default Routes;
MainLayout.js
import React from "react";
//var reactRouterToArray = require("react-router-to-array");
const MainLayout = props => {
//console.log(reactRouterToArray(props.children));
return <div>{props.children}</div>;
};
export default MainLayout;
Sidebar doesn't open the content inside the main container instead it opens in a new tab if i use route inside routes.js .
Sidebar doesn't open the content if i use route inside AdminDash.js .
i have tried passing the routes using props (props.children) to AdminDash( its not receivng the prop)
I am using private and public routes.
I am confused and I don't know where am I going wrong any suggetions , or hints would be helpful.
Thanks in advance.
Sidebar doesn't open the content inside the main container instead it opens in a new tab if i use route inside routes.js .
Inside LeftDrawer you are rendering links to the content. You should use react-router-dom Link elements.
Like this:
import { Link } from 'react-router-dom'
<Link to="/about">About</Link>
Sidebar doesn't open the content if i use route inside AdminDash.js .
Routes shouldn't be defined multiple times. You have defined /admin/pagedashboard both in AdminDash.js and Routes.js. If you want to have a shared shell around the content, define routes inside the shell component and remove exact route from the parent routes.
Example:
MainLayout
.Routes
../admin
...AdminDash (Shell for multiple pages, admin layout)
..../admindashboard
.....AdminDasboard
..../pagedashboard
.....PageDashboard
i have tried passing the routes using props (props.children) to AdminDash( its not receivng the prop)
You should just import them when needed.
EDIT:
Remove exact from the Routes.js <Route path='/admin' component={AdminDash} /> and in AdminDash try
const AdminDash = ({ match }) => (
<div>
<Route path={${match.url}/admindashboard} component={AdminContent}/>
<Route path={${match.url}/pagedashboard} component={PageContent}/>
</div>
);
In the above example take note to change AdminContent and PageContent with the names of your components.

React-Router-Dom | URL Changes, but the component doesn't update

I have a list of items, in a table in React. When I click on the table Link, the url updates, but the component doesn't get rendered. If I refresh the component is there.
I have read that some React-router-dom versions have some problems, and there are a lot of solutions that are being discussed here:
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
That although is for the Beta Versions. I assume I need to do something with the higher order function withRouter from react-router-dom, but it doesn't work for me. On top of that, withRouter has been set up globally in the App.
const AppHeader = withRouter(({ history, location, ...props }) => (
<Header {...props} currentRoute={location.pathname} />
));
The thing is, my App has several applications. One Angular and 2 React ones. Do I need to set it up, on each application as well? This is the Parent Component with the router for the application the Links aren't working.
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import 'react-tagsinput/react-tagsinput.css';
import PolicyRoutes from 'dataprotection/policies/containers/PolicyRoutes';
import './styles.scss';
const AppRouter = () => (
<Switch>
<Route exact path="/policies" component={PolicyRoutes} />
<Redirect to="/policies" />
</Switch>
);
AppRouter.propTypes = {};
function mapStateToProps() {
return {};
}
export default connect(mapStateToProps)(AppRouter);
I have tried 2 solutions. The first is to actually wrap my component withRouter like so:
<Route exact path="/policies" component={withRouter(PolicyRoutes)} />
And the second is to wrap withRouter, the connect function. Both aren't working.
This is the component not working:
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';
import OverviewScreen from '../OverviewScreen';
import PolicyDetailsScreen from '../PolicyDetailsScreen';
const PolicyRoutes = ({ match }) => (
<Switch>
<Route exact path={`${match.url}/details/:policyId`} component={PolicyDetailsScreen} />
<Route exact path={match.url} component={OverviewScreen} />
<Redirect to={match.url} />
</Switch>
);
PolicyRoutes.propTypes = {
match: PropTypes.object
};
export default PolicyRoutes;
Can anyone help? I don't know what the problem is...

How to pass a default params or state to the react router? any alternative approach?

I have a state that is list of valid name (valid_list = []). I want to route to home page if someone types a /topics/:name which is not valid. I want o hence pass the valid list to the new component.
I have mentioned all my attempts at the end.
My parent component is this:
import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Topic from '../topic'
class App extends Component { {
return (
<Router>
<div>
<Route path="/topics/:name" component={Topic} />
</div>
</Router>
);
}
the calling component is
import React,{ Component } from 'react'
import { Link } from 'react-router-dom'
class Maintopic extends Component { {
render() {
return (
<div>
<Link to='/topic:$name' > NextTopic </Link>
</div>
);
}
and called component is something where I am facing issues.
render() {
return (
<div>
<h1>{this.props.match.params.name}</h1>
</div>
);
}
Attempt 1:
Passing object to link:
<Link to={
{
pathname:`/topic/${name}`,
state:{
valid_list : this.state.valid_list
}
}}>
And then performing check on the called component by using artlist this.props.location.state.valid_list,
Here the problem is if I manually type URL like "/topic/name1" or "/topic/name2" i get error like "TypeError: Cannot read property 'valid_list' of undefined"
Attempt 2:
Having called and calling component both have manually stored state in their component
Here issues is I really want my valid_list to be dynamic and can be increased visa input button in future implementation. Plus it does not make sense to maintain different copies of same data.
If your valid_list is an array of stuff, one solution for your problem is making a decorator and decorates your component, so you should do it like this.
const withValidList = (valid_list) => (Component) => (routerProps) => {
return <Component {...routerProps} valid_list={valid_list} />
}
then in your <Route> you must decorate your component with the valid_list like this
import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Topic from '../topic'
class App extends Component { {
return (
<Router>
<div>
<Route path="/topics/:name" component={withValidList(['list1', 'list2'])(Topic)} />
</div>
</Router>
);
}
that's should works, so basically your are wrapping your component adding some extra functionality with the decorator pattern, that give you the ability to passing down the valid_list props to be used into the Topic component.

Categories