react router takes two click to update the route - javascript

I have used react-router v4 for routing in my application. I have used routing to show various form like for showing apartment form, experience form, login, register etc.
Problem
When i click on apartment image, react router routes to apartment form. The route becomes /apartment. If i again then click on register button, the route do not get updated. I have to double click on register button to update the route to /register.
Here is my code
class App extends Component {
constructor(props, context) {
super(props, context);
console.log('context', context);
this.state = { show: false };
}
showModal(e) {
e.preventDefault();
this.setState({ show: true });
}
hideModal() {
this.setState({ show: false });
}
render() {
return (
<div className="container-fluid">
<Nav
showModal={(e) => this.showModal(e)}
hideModal={() => this.hideModal()}
show={this.state.show}
onHide={() => this.hideModal()}
/>
</div>
);
}
}
App.contextTypes = {
router: React.PropTypes.object
};
const Nav = (props) => (
<Router>
<div>
<nav className="navbar navbar-default">
<div className="container-fluid">
<div className="navbar-header">
<a className="navbar-brand" href="">
<img
alt="Brand"
className="img-responsive"
src={logo}
role="presentation"
/>
</a>
</div>
<div className="collapse navbar-collapse" id="collapse-1">
<ul className="nav navbar-nav navbar-right nav-social-icon">
<li className="dropdown">
<a
href=""
className="dropdown-toggle"
data-toggle="dropdown"
>
ES
<span className="caret" />
</a>
<ul className="dropdown-menu" style={{ color: '#000', fontWeight: 'bold' }}>
<li onClick={() => props.selectedLocale('en')}>
en
</li>
<li onClick={() => props.selectedLocale('es')}>
es
</li>
</ul>
</li>
<li className="btn-group regLog">
<button
className="btn btn-default"
onClick={props.showModal}
>
<Link to={{ pathname: '/signup' }}>
{props.intl.formatMessage({ id: 'nav.registration.text' }) }
</Link>
</button>
<button
onClick={props.showModal}
className="btn btn-default"
>
<Link to={{ pathname: '/login' }}>
{props.intl.formatMessage({ id: 'nav.login.text' }) }
</Link>
</button>
{props.show ?
<ModalForm
show={props.show}
onHide={props.onHide}
/> : <span />
}
</li>
</ul>
</div>
</div>
</nav>
</div>
</Router>
);
class ModalForm extends Component {
render() {
const { show, onHide, intl } = this.props;
return (
<Router>
<Modal
{...this.props}
show={show}
onHide={onHide}
dialogClassName="custom-modal"
>
<Modal.Header closeButton>
<Link to='/login' className="logTitle">
<Modal.Title id="contained-modal-title-lg">
{intl.formatMessage({ id: 'nav.login.text' })}
</Modal.Title>
</Link>
<Link to='/signup' className="logTitle">
<Modal.Title id="contained-modal-title-lg">
{intl.formatMessage({ id: 'nav.registration.text' })}
</Modal.Title>
</Link>
</Modal.Header>
<Modal.Body>
<Match pattern='/login' component={Login} />
<Match pattern='/signup' component={Signup} />
</Modal.Body>
</Modal>
</Router>
);
}
}
I think its because of using onClick event and routing. How can i solve it?
UPDATE
I tried to use router context but i am getting undefined. App is a parent component and Nav is a child component. Nav component uses router while onClick functions are handled in App component where this.context.router has to be handled.
Thanks

Put the redirect on onClick function using router context ...
https://github.com/ReactTraining/react-router/blob/master/docs/API.md#routercontext
You use contextTypes from react to access router from react-router and the n use push to change url

I am also using RRv4, to handle button links as you have then I wrap the button in the link. The put the overall click handler on the link. This should call prior to the transition and if you need to prevent transition you can simply call e.preventDefault
This will maintain the declarative nature of RRv4 and prevent the need to use the experimental context feature in react.

Related

Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. in react v6

Hello I'm new to react and got myself stuck here, my version is v6 and hence having a bit of a problem understanding, I'm following a tutorial from udemy
The error that occurred is - Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
this is in my Home.js
class Dashboard extends Component {
constructor(props) {
super(props);
this.state = {
child: props.nestedRoute,
search: "",
};
}
componentDidMount() {
this.activeNav();
}
activeNav() {
const pathname = window.location.pathname;
const possibleRoutes = [
{ routes: "/dashboard", targetId: "home" },
{ routes: "/addProduct", targetId: "addProduct" },
{ routes: "/products", targetId: "products" },
{ routes: "/profile", targetId: "profile" },
];
possibleRoutes.forEach(({ route, targetId }) => {
window.jQuery(`#${targetId}`).removeClass("active");
if (route === pathname) {
window.jQuery(`#${targetId}`).addClass("active");
}
});
}
render() {
const Child = this.state.child
console.log(Child)
const { user } = this.props.auth;
return (
<div id="content-wrapper" className="d-flex flex-column">
<div id="content">
<nav className="navbar navbar-expand navbar-light bg-white topbar mb-44 static-top shadow">
<ul className="navbar-nav ml-auto">
<li className='nav-item dropdown no-arrow'>
<Link
className="nav-link dropdown-toggle"
to="#"
id="userDropdown"
role="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
<span className="mr-2 d-none d-lg-inline text-gray-600 small">
{user.name}
</span>
<Avatar size={40}>
{user.name && this.avatarText(user.name)}
</Avatar>
</Link>
<div
className="dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="userDropdown"
>
<Link className="dropdown-item" to="#">
<i className="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</Link>
<Link className="dropdown-item" to="#">
<i className="fas fa-cogs fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</Link>
<Link className="dropdown-item" to="#">
<i className="fas fa-list fa-sm fa-fw mr-2 text-gray-400"></i>
Activity Log
</Link>
<div className="dropdown-divider"></div>
<Link
className="dropdown-item"
to="#"
onClick={this.logUserOut}
>
<i className="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</Link>
</div>
</li>
</ul>
</nav>
<Child {...this.props} search={this.state.search} />
</div>
</div>
);
}
}
Dashboard.propTypes = {
auth: PropTypes.object.isRequired,
logout: PropTypes.func.isRequired,
};
const mapStateToProps = (state) => ({
auth: state.auth,
});
export default connect(mapStateToProps, { logout })(Dashboard);
my App.js looks like this
function App(props) {
useEffect(() => {
store.dispatch(setCurrentUser())
}, [])
return (
<Provider store={store}>
<Router>
<Routes>
<Route exact path="/" element={<Landing/>} />
<Route exact path="/" element={<ProtectedRoute/>}>
<Route exact
path="/dashboard"
element={()=> (<Dashboard {...props} nestedRoute={Home} />)}
/>
<Route exact
path="/dashboard/addProduct"
element={()=> (<Dashboard {...props} nestedRoute={AddProduct} />)}
/>
</Route>
<Route exact path="/register" element={<Register/>} />
<Route exact path="/login" element={<Login/>} />
</Routes>
</Router>
</Provider>
);
}
In your react router use the render method.
<Route exact
path="/dashboard/addProduct"
render={()=> <Dashboard {...props} nestedRoute={AddProduct} />}
/>

React Router hide App content when click other pages link

I want to hide app component content when I click on other component pages link.
Right now, when I click other links like about us, then it shows both app component and about us page component. But I want show only about us content once I click on about us page.
Also, when I define App component patch as a "/" then application keeps loading.
Below are the code
App.js
import React, { Component } from "react";
import Navigation from "./components/Navigation";
import data from "./data";
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
// data: false
};
}
render() {
return (
<div className="container">
<Navigation />
{data.map((link) => (
<div className="card mb-3" key={link.Title}>
<div className="row no-gutters">
<div className="col-md-5">
<img
src={require("./images/" + link.Img)}
className="card-img"
alt=""
/>
</div>
<div className="col-md-7">
<div className="card-body">
<h5 className="card-title">{link.Title}</h5>
<p className="card-text">{link.Desc.halfDesc}</p>
<p className="card-text">
<small className="text-muted">{link.date}</small>
</p>
<button type="button" className="btn btn-dark float-right">
Read More
</button>
</div>
</div>
</div>
<FullDescription />
</div>
))}
</div>
);
}
}
const FullDescription = (props) => (
<div className="modalbox">
<p>fsdf</p>
</div>
);
export default App;
Navigation.Js Everything is working fine only App home page content show which i don't want when i click other pages
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import Api from "./Api";
import News from "./News";
import Website from "./Website";
class Navigation extends Component {
render() {
return (
<Router>
<ul className="nav justify-content-center mb-4 navigation">
<li className="nav-item">
<Link className="nav-link" to="/Api">
Api
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/News">
News
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/Website">
Website
</Link>
</li>
</ul>
<Switch>
<Route exact path="/Api" component={Api}></Route>
<Route exact path="/News" component={News}></Route>
<Route exact path="/Website" component={Website}></Route>
</Switch>
</Router>
);
}
}
export default Navigation;
For this to work you need to put content of app.js inside another component because right now it doesnt have a route to hide itself when going to other page. So you need to treat the component just like your rest components (Api.js, News.js) etc..
NewAppComponent.js
import React, { Component } from "react";
import { Link } from "react-router-dom";
class Navigation extends Component {
render() {
return (
<ul className="nav justify-content-center mb-4 navigation">
<li className="nav-item">
<Link className="nav-link" to="/Api">
Api
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/News">
News
</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/Website">
Website
</Link>
</li>
</ul>
);
}
}
export default Navigation;
App.js
import React, { Component } from "react";
import Navigation from "./components/Navigation";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import NewAppComponent from "./NewAppComponent";
import Api from "./Api";
import News from "./News";
import Website from "./Website";
class App extends Component {
render() {
return (
<div className="container">
<Router>
<Navigation />
<Switch>
<Route exact path="/" component={NewAppComponent}></Route>
<Route path="/Api" component={Api}></Route>
<Route path="/News" component={News}></Route>
<Route path="/Website" component={Website}></Route>
</Switch>
</Router>
</div>
);
}
}
export default App;
NewAppComponent.js
// NewAppComponent.js
import React, { Component } from "react";
import data from "./data";
class NewAppComponent extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
// data: false
};
}
render() {
return (
<div className="container">
{data.map((link) => (
<div className="card mb-3" key={link.Title}>
<div className="row no-gutters">
<div className="col-md-5">
<img src={require("./images/" + link.Img)} className="card-img" alt="" />
</div>
<div className="col-md-7">
<div className="card-body">
<h5 className="card-title">{link.Title}</h5>
<p className="card-text">{link.Desc.halfDesc}</p>
<p className="card-text">
<small className="text-muted">{link.date}</small>
</p>
<button type="button" className="btn btn-dark float-right">
Read More
</button>
</div>
</div>
</div>
<FullDescription />
</div>
))}
</div>
);
}
}
const FullDescription = (props) => (
<div className="modalbox">
<p>fsdf</p>
</div>
);
export default NewAppComponent;

How can I pass values from a functional component through a React Router Link to another functional component?

How can I pass values from my ResultItem.js component, to my Result.js component using React Router's Link component?
ResultItem.js
export default function ResultItem({ result }) {
//desctructure the result elements
const {
title,
type,
id,
publisher,
volume,
issue,
page_number,
year_published,
} = result;
return (
<>
<div className="card grey lighten-4" style={{ padding: '1rem' }}>
<span className="badge green white-text">{type}</span>
<h5>{title}</h5>
<h6>Publisher: {publisher}</h6>
<h6>Volume: {volume}</h6>
<h6>Issue: {issue}</h6>
<h6>Page Number: {page_number}</h6>
<h6>Year Published: {year_published}</h6>
<div>
<Link
to={`/${id}`}
className="waves-effect waves-light btn-small blue"
>
Read More
</Link>
</div>
</div>
</>
);
}
Result.js
export default function Result({ title }) {
return (
<>
<div className="container">
<h5>
More information about that thing you just clicked on will be on this
page.
</h5>
<h1>title = {title}</h1>
</div>
</>
);
}
App.js
<Route path="/:id" component={Result} />
<Link to={{
pathname: `/item/${item.id}`,
state: {id: item.id}
}}>
Later you call: {id.id} in Result
Does it works?

Reactjs Dropdown Menu not showing

I'm creating with reactjs Navbar which should include an dropdown menu component. I took the example from react bootstrap.
import React from 'react';
import {NavDropdown} from 'react-bootstrap'
export default function Dropdown() {
return (
<>
<div className="dropdown-style">
<NavDropdown title="Dropdown" id="collasible-nav-dropdown">
<NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.2">Another action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.Item href="#action/3.4">Separated link</NavDropdown.Item>
</NavDropdown>
</div>
</>
)
}
But when I run this code the dropdown menu does not open in the front.
But the dev-mode shows me that it's actually opening.
The dropdown menu is only showing when I'm including this css-style
.dropdown-style{
position: absolute;
But when I shrink the window then this component tears up the whole navbar when I merge it to the burger menu
I tried
{ .z-index: 999 }
But this didn't work.
Here is the navigation component
export default class Navbar extends Component {
state = {
isOpen: false
};
handleToggle = () => {
this.setState({ isOpen: !this.state.isOpen });
};
render() {
return (
<nav className="navbar">
<div className="nac-center">
<div className="nav-header">
<Link to="/">
<img src={logo} alt="foo" id="foo" />
</Link>
<button
type="button"
className="nav-btn"
onClick={this.handleToggle}
>
<FaAlignRight className="nav-icon" />
</button>
</div>
<div className="ul-width nav-font">
<ul
className={this.state.isOpen ? "nav-links show-nav" : "nav-links nav-terms"}
>
<li className="navbar-top">
<Link to="/support"
onClick={(this.state.isOpen) ? this.handleToggle : null}>
Support
</Link>
</li>
<li className="navbar-top">
<Link to="/aboutus"
onClick={(this.state.isOpen) ? this.handleToggle : null}>
<nobr>About Us</nobr>
</Link>
</li>
<li className="navbar-top">
<Link to="/foo"
onClick={(this.state.isOpen) ? this.handleToggle : null}>
foo
</Link>
</li>
<li className="navbar-top">
<Dropdown/>
</li>
</ul>
</div>
</div>
</nav>
);
}
}
I've found out for myself now.
If one of you have the same problem, just overwrite the css-class with .dropdown-menu { position:relative !important }
it seems that dropdown-menu is written by react itself and you just have to overwrite it.

Prevent nested <Link/> component from inheriting path from previous <Link/> (React router 4)

I have a Dasboard component where I have React-router
<Link/> components that are linking to
http:<procjethos>/team
Inside <Team/> component I have a <Link/> components that should link to
http:<projecthost>/list/:listId
But instead, it inherits from previous link and I get
http<projecthost>/team/list/:listId
// Dashboard.jsx
render() {
const { shoppingLists, teams } = this.props;
return (
<Fragment>
<Toolbar isHomePage/>
<div className="wrapper">
<div className="dashboard">
<h2 className="dashboard__heading">
<TeamIcon />
Cohorts
</h2>
<ul className="dashboard__list">
{_map(teams, team => (
<li className="dashboard__list-item" key={team._id}>
<Link to={`team/${team._id}`}>
<CardItem name={team.name} />
</Link>
</li>
))}
</ul>
</div>
</div>
</Fragment>
);
// Team.jsx
<Fragment>
<Toolbar />
<div>
Cohort of id:
{id}
<ul>
{_map(lists, list => (
<li className="dashboard__list-item" key={list._id}>
<Link to={`list/${list._id}`} replace>
<CardItem name={list.name} />
</Link>
</li>
))}
</ul>
</div>
</Fragment>
How to achieve the desired behavior in React-Router 4 with nested LINKs?
Add a / before link path
<Link to={`/list/${list._id}`} replace>
<CardItem name={list.name} />
</Link>

Categories

Resources