You should not use Link outside a Router using react-router-dom - reactjs

I am trying to do routing using react-router-dom. I got an error like you should not use outside the like this.Here below i am attaching my code please check.
index.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createLogger } from 'redux-logger'
import App from './containers/App';
render(
<Provider>
<App/>
</Provider>,
document.getElementById('root')
)
App.js
import React from 'react';
import Dropdown from './dropdown';
import './styles.css';
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
import Home from './Home';
import Addatttemp from './Addatttemp';
const options = [
{label: 'One' },
{label: 'Two'},
{label: 'Three'},
{label: 'Four' }
]
const AgentValues=[
{label: 'Add Att/temp', value:'Addatttemp' },
{label: 'Mod prof LVL',value:'Modproflvl'},
{label: 'Override Attr',value:'Overrideattr'},
{label: 'Temp',value:'temp'}
]
const defaultOption = options[0]
export default class App extends React.Component {
constructor (props) {
super(props)
}
render() {
return (
<div>
<div className="navbar">
<div className="align">
<div className="dropdown">
<Dropdown options={AgentValues} name='Agent'/>
</div>
<div className="dropdown">
<Dropdown options={options} name='Templete'/>
</div>
<div className="dropdown">
<Dropdown options={options} name='Report'/>
</div>
<div className="dropdown">
<Dropdown options={options} name='Search'/>
</div>
</div>
</div>
<Router>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/Agent/Addatttemp' component={Addatttemp} />
</Switch>
</Router>
</div>
);
}
}
Dropdown.js
import React, { Component, PropTypes } from "react";
import { Link } from 'react-router-dom';
class dropdown extends Component {
constructor (props) {
super(props)
}
render(){
var dropdownList = []
this.props.options.map((res)=>{
dropdownList.push(<Link to={'/'}>{res.label}</Link>)
})
return(
<div>
<button className="dropbtn"><Link to={'/'}>{this.props.name}</Link>
</button>
<div className="dropdown-content">
{dropdownList}
</div>
</div>
)
}
}
export default dropdown;
Home.js
import React from 'react'
const Home = () => (
<div>
<h1>Welcome to the Tornadoes Website!</h1>
</div>
)
export default Home
Addatttemp.js
import React from 'react'
const AddTemp = () => (
<div>
<h1>Welcome to the Add att/temp!</h1>
</div>
)
export default AddTemp
Like this i wrote my code, but when i run this code it throws me the error like Uncaught Error: You should not use Link outside a Router . I am unable to resolve this, please give me suggestions that what i did wrong in it, Any help much appreciated.

As the error message says you are not having Router up the component tree.
You could use it in App component like this
export default class App extends React.Component {
render() {
return (
<Router>
<div>
<div className="navbar">
<div className="align">
<div className="dropdown">
<Dropdown options={AgentValues} name='Agent'/>
</div>
<div className="dropdown">
<Dropdown options={options} name='Templete'/>
</div>
<div className="dropdown">
<Dropdown options={options} name='Report'/>
</div>
<div className="dropdown">
<Dropdown options={options} name='Search'/>
</div>
</div>
</div>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/Agent/Addatttemp' component={Addatttemp} />
</Switch>
</div>
</Router>
);
}
}
Also
You don't need constructor that just calls super
// this is noop
constructor (props) {
super(props)
}
You don't need to push to external array when using map.
var dropdownList = this.props.options.map(res => (
<Link to={'/'}>{res.label}</Link>
))

If you are trying to show a Link on a page or any element outside of BrowserRouter you are going to get this error. This error message is saying that any component that is not a child of a router cannot contain any react-router-dom related components.
What you need to learn for effective development in React is your component hierarchy.
In your case your parent component, the one at the top of the hierarchy is App, how do I know? because you said so right here in your index.js file:
render(
<Provider>
<App/>
</Provider>,
document.getElementById('root')
)
So, when working with react-router-dom, next up on that hierarchy chart should be your BrowserRouter. This is where you start to lose me and React as we are both looking for BrowserRouter inside your App component and do not see it.
This is what we should be seeing right now:
const App = () => {
return (
<div className="ui container">
<BrowserRouter>
<div>
<Route path="/" exact component={Home} />
<Route path="/Agent/Addatttemp" exact component={Addattemp} />
</div>
</BrowserRouter>
</div>
);
};
Notice I am using the exact keyword? I am using the exact keyword so I don’t accidentally match one of these other routes I am about to implement.
So please go ahead and add your BrowserRouter or in your case, your Router which is acting as BrowserRouter higher up on that hierarchy below App, it has to be next up in the hierarchy, everything else is a child of that BrowserRouter and must go within it.
And since you are never going to make use of the Link from react-router-dom inside your App component, go ahead and clean it up like so:
import { BrowserRouter, Route } from "react-router-dom";
Once you follow the above, that error should go away.

Related

React-router URL changes but page is still unchanged

I am new to react and react-router, so please go easy on me.
I am trying to implement router in my Todo List project, where path="/" takes me to my todo list and path="/id" takes me to a test page (later will show the description of the task).
When I click the link that takes me to "/id", the URL in the browser changes but the page/content doesn't. However, when I refresh my browser, the test page loads.
I have put the Switch in App.js shown below.
import React, { Component } from "react";
import "./App.css";
import TodoList from "./components/TodoList";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Test from "./components/Test";
class App extends Component {
render() {
return (
<Router>
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route exact path="/" component={TodoList} />
<Route path={`/id`} component={Test} />
</Switch>
</div>
</Router>
);
}
}
export default App;
And I have put the Link to "/id" as shown below in a child component of component which is called here in App.js.
<div key={todo.id}>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
</div>
Am I missing something which is causing my component to not load when I click the link?
Edit: Here's a link to my project. https://stackblitz.com/edit/react-7cpjp9?file=src/index.js
Issue
Ok, the issue is exactly as I had suspected. You are rendering multiple routers in your app. The first is a BrowserRouter in your index.js file, the second, another BrowserRouter in App.js, and at least a third BrowserRouter in Todo.js. You need only one router to provide a routing context for the entire app.
The issue here is that the router in Todo component is the closest router context to the links to specific todo details. When a link in Todo is clicked, this closest router handles the navigation request and updates the URL in the address bar. The blocks, or "masks", the router in App component or index.js that is rendering the routes from "seeing" that a navigation action occurred. In other words, the URL in the address bar is updated by the inner router, but the outer router doesn't know to render a different route.
Solution
Keep the BrowserRouter wrapping App in index.js and remove all other routers used in your app.
App - Remove the Router component. Also, reorder the routes/paths from most specific to least specific so you don't need to specify the exact prop on every route. Allows more specific paths to be matched and rendered before less specific paths by the Switch component.
class App extends Component {
render() {
return (
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route path="/id/:todoId" component={Test} />
<Route path="/" component={TodoList} />
</Switch>
</div>
);
}
}
Todo - Remove the Router component. Move the key={todo.id} up to the outer-most element so when todos array is updated React can reconcile updates.
class Todo extends Component {
constructor(props) {
super(props);
this.state = {
id: null,
value: "",
details: "",
};
this.submitUpdate = this.submitUpdate.bind(this);
}
submitUpdate(value) {
const { updateTodo } = this.props;
updateTodo(this.state.id, value);
this.setState({
id: null,
value: "",
});
}
render() {
const { todos, completeTodo, removeTodo } = this.props;
if (this.state.id) {
return <TodoForm edit={this.state} onSubmit={this.submitUpdate} />;
}
return todos.map((todo, index) => (
<div
className={todo.isComplete ? "todo-row complete" : "todo-row"}
key={todo.id}
>
<div>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
</div>
<div className="icons">
<RiCloseCircleLine
onClick={() => removeTodo(todo.id)}
className="delete-icon"
/>
<TiEdit
onClick={() => this.setState({ id: todo.id, value: todo.text })}
className="edit-icon"
/>
<RiCheckboxCircleLine
onClick={() => completeTodo(todo.id)}
className="delete-icon"
/>
</div>
</div>
));
}
}
First of all the approach, you are taking for dynamic routing is wrong.
It should be like this you will have to add the exact keyword on the dynamic route.
<Route exact path="/id/:todoId" component={Test} />
And
<div key={todo.id}>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
import React, { Component } from "react";
import "./App.css";
import TodoList from "./components/TodoList";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Test from "./components/Test";
class App extends Component {
render() {
return (
<Router>
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route exact path="/" component={TodoList} />
**<Route exact path={`/id`} component={Test} />**
</Switch>
</div>
</Router>
);
}
}
export default App;

Routing in React JS on click

I am new to React and I want to navigate to another component on button click. I just want to perform a simple routing. This is the code that I tried. But I am not able to route it.
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
import Hello from './HelloComponent';
class App extends Component {
constructor(props) {
super(props);
this.try = this.try.bind(this)
}
try = () => {
alert();
<div>
<Router>
<Route path="/hello" component={Hello} />
</Router>
</div>
}
render() {
return (
<div className="App">
<div className="container">
<button id="b1" onClick={this.try}>Click me</button>
</div>
</div>
);
}
}
export default App;
Please help me with this code to perform basic routing in react JS
You cannot return JSX to onClick handler since it won't do anything with it.
You need to configure your Routes in render in advance and use history.push to change the Route
Below is a sample code that you can refer
import React, { Component } from 'react';
import { BrowserRouter as Router, Route,Switch, Redirect} from 'react-router-dom'
import Hello from './HelloComponent';
class App extends Component {
try = () => {
this.props.history.push('/hello');
}
render() {
return (
<div className="App">
<div className="container">
<button id="b1" onClick ={this.try}>Click me</button>
<Route path="/hello" component={Hello}/>
</div>
</div>
);
}
}
export default () => (
<div>
<Router>
<Route component={App} />
</Router>
</div>
);
I recommend you look at the doc.
<Route path="/hello" component={Hello}/> will display the component Hello exactly where the <Route/> is, but I think your function will do nothing here as it returns a <div> but where does it go?
You need some sort of "higher" component that will render your routes, then call a <Link/>
Then try nesting the button inside the <Link/> ?
<Link to="/??">
<button id="b1">
Click me
</button>
</Link>
in your code
try = () => {
alert();
<div>
<Router>
<Route path="/hello" component={Hello}/>
</Router>
</div>
}
your just pushing the route and it's not a action to take you to different page
bellow code will work fine and it's good practice to place router in separate component. click here you can find this code in codesandbox
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "./styles.css";
function RouterComponet() {
return (
<Router>
<Switch>
<Route exact path="/" component={App} />
<Route path="/user" component={User} />
</Switch>
</Router>
);
}
class App extends Component {
constructor(props) {
super(props);
}
onClick = () => {
this.props.history.push("/user");
};
render() {
return (
<div>
<h1>App component</h1>
<a onClick={this.onClick} className="link">
click here
</a>{" "}
to user page
</div>
);
}
}
class User extends Component {
constructor(props) {
super(props);
}
onClick = () => {
this.props.history.push("/");
};
render() {
return (
<div>
<h1>User Componet</h1>
<a onClick={this.onClick} className="link">
click here
</a>{" "}
to back
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<RouterComponet />, rootElement);
I have created a demo that brings it all together. It has three files App.js, About.js, Contacts.js. To Navigate to any component, you need to add its route in App.js, Then depending on the location of your button (About.js), wrap it with Link that helps the element navigate to the specified route. When clicked, the Contacts component should be loaded. Hope this helps. code demo
App.js
import React from "react";
import { Switch, Route, BrowserRouter } from "react-router-dom";
import About from "./About";
import Contact from "./Contacts";
function App() {
return (
<BrowserRouter>
<Switch>
<Route path="/" component={About} exact />
<Route path="/contacts" component={Contact} />
</Switch>
</BrowserRouter>
);
}
export default App;
About.js
import React from "react";
import { Link } from "react-router-dom";
function About() {
return (
<div>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry.
</p>
<Link to="/contacts">
<button>click me</button>
</Link>
</div>
);
}
export default About;
Contacts.js
import React from "react";
function Contact() {
return <div>Call me!!</div>;
}
export default Contact;
This is the first SO post on google, so I'd like answer the question with updated coding style and answer:
From react v6 you use the useNavigation hook. (Reference)
import { useNavigate } from 'react-router-dom';
export const MyComponent = () => {
const navigate = useNavigate();
return (
<>
<button
onClick={() => {
navigate('/');
}}
>
click me
</button>
</>
);
};

Routes not working in react-router v4

I am trying to setup react router in my react application. The versions I am using are
"react-dom": "^16.2.0",
"react-redux": "^5.0.6",
"react-router-dom": "^4.2.2",
"react-router-redux": "^5.0.0-alpha.9",
"redux": "^3.7.2",
I am using reacr-router-redux for this appilication.
Application Flow: I have two pages in my application: Login Page and App Page. Landing page should be Login Page and when I click on Login button then it should take me to the App Page. There are three sections in App Page: Header, Sidebar and Content Section. Content section is dynamic and renders two different layouts depending on which link is clicked in sidebar. Only one component at a time can be rendered in content section.
Problem: I have defined routes. I get landed to LoginPage correctly. When I click to Login, I get navigated to app page also correctly. But when I click a link on sidebar, all the components (sidebar, header and content section) disappears.
My code
main index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import registerServiceWorker from './registerServiceWorker';
import Root from './Container/Root'
import {Provider} from 'react-redux'
import {ConnectedRouter} from 'react-router-redux'
import store, {history} from './store'
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<div>
<Root />
</div>
</ConnectedRouter>
</Provider>,
document.getElementById('root'));
registerServiceWorker();
Root/index.js
import React, {Component, PropTypes } from 'react'
import { Provider } from 'react-redux'
import LoginPage from '../../Pages/LoginPage'
import App from '../../Container/App/App'
import { Route, Link } from 'react-router-dom'
const styles = {
container: {
height: '100vh',
width : '100vw',
position: 'relative'
}
}
class Root extends Component {
render () {
return (
<div>
<div>
<main>
<Route exact path="/" component={LoginPage} />
<Route exact path="/app" component={App} />
</main>
</div>
</div>
)
}
}
export default Root
App.js (here's where the problem is)
import React, { Component } from 'react';
import { Route, Link } from 'react-router-dom'
import Sidebar from '../../Components/Sidebar'
import TriviaPanel from '../../Components/TriviaPanel'
import Header from '../../Components/Header'
import ImagePanel from '../../Components/ImagePanel'
import LoginPage from '../../Pages/LoginPage'
class App extends Component {
render() {
return (
<div>
{/*<LoginPage/> */}
<Header/>
<Sidebar/>
<div>
<main>
<Route component={TriviaPanel} />
<Route exact path="/trivia" component={TriviaPanel} />
<Route exact path="/image" component={ImagePanel} />
</main>
</div>
</div>
);
}
}
export default App;
MenuPanel/index.js (This is the sidebar I change the content component from)
import React, { Component } from 'react';
import { push } from 'react-router-redux'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
const styles = require('./sidebar.css');
class MenuPanel extends Component {
constructor(){
super();
this.state = {
activePanel: "trivia"
}
}
toImagePage(){
this.setState({activePanel:"image"},()=>{
this.props.toImagePage()
})
}
toTriviaPage(){
this.setState({activePanel:"trivia"},()=>{
this.props.toTriviaPage()
})
}
render() {
return (
<div>
<div className="navbar-side">
<div className="tessact-logo"></div>
<div className={`navbar-item ${this.state.activePanel == "trivia"? "active":""}`} onClick={() => this.toTriviaPage()}>
<a className="navbar-item-link"><span className="fa fa-comment"></span> TRIVIA</a>
</div>
<div className={`navbar-item ${this.state.activePanel == "image"? "active":""}`} onClick={() => this.toImagePage()}>
<a className="navbar-item-link"><span className="fa fa-picture-o"></span> IMAGES</a>
<div className="navbar-item-inside">
<a className="navbar-item-inside-link">PERSONSS</a>
<a className="navbar-item-inside-link">BRANDS</a>
<a className="navbar-item-inside-link">OBJECTS</a>
</div>
</div>
<div className="navbar-item">
<a className="navbar-item-link"><span className="fa fa-tags"></span> KEYWORDS</a>
</div>
</div>
</div>
);
}
}
const mapDispatchToProps = dispatch => bindActionCreators({
toTriviaPage: () => push('/trivia'),
toImagePage: () => push('/image')
}, dispatch)
export default connect(
null,
mapDispatchToProps
)(MenuPanel)
I tried this also
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
{/*<LoginPage/> */}
<Header/>
<Sidebar/>
<switch>
<Route exact path="/trivia" component={TriviaPanel}/>
<Route exact path="/image" component={ImagePanel}/>
</switch>
<Route component={TriviaPanel}/>
</div>
</BrowserRouter>
);
}
}
export default App;
What is wrong in what I am doing? In previous versions of router it was pretty simple to define child routes and everything. I am new to this router v4.
The problem is with your routes. i faced the same problem recently. so here is your problem. you clicked the link for 'app'. the url becomes
http://localhost/app
now all routes defined inisde the app component must be /app/link.
therefore
<link to='/trivia'>Trivia</link> //example. use whatever metohd you are using to route instead. use the given url
<Route exact path="/trivia" component={TriviaPanel}/>
becomes
<link to='/app/trivia'>Trivia</link>
<Route exact path="/app/trivia" component={TriviaPanel}/>
this tells react that it needs to go into the app component and then search for the route tag in its jsx to render.

activeClassName of react-router v4 not working appropriately

I am very new to react-routing. After reading the docs and reading some articles this is how structured my routing. Please correct me if I am doing wrong.
Using react-router V4
Routes.js
import React from 'react';
import App from '../app/components/App';
import Dashboard from '../dashboard/components/Dashboard';
import Contact from '../dashboard/components/Contact';
import Account from '../dashboard/components/Account';
import Career from '../dashboard/components/Career';
import NoMatch from './NoMatch';
import { Provider } from 'react-redux';
import { Route, BrowserRouter, Switch, Redirect } from 'react-router-dom';
const Root = ({ store }) => (
<Provider store={store}>
<BrowserRouter>
<div>
<Route path="/app" component={App} />
<Switch>
<Route path="/app" exact component={Dashboard} />
<Route path="/app/home/dashboard" component={Dashboard} />
<Route path="/app/home/contact" component={Contact} />
<Route path="/app/home/account" component={Account} />
<Route path="/app/home/career" component={Career} />
<Route component={NoMatch} />
</Switch>
</div>
</BrowserRouter>
</Provider>
)
export default Root
I used /app 2 times. First is to load always as it has sidenav and header. Then inside switch I used to load default component dashboard.
App.js
import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.css';
import 'font-awesome/css/font-awesome.min.css';
import Header from './Header';
import SideNav from './SideNav';
class AppComp extends Component {
componentDidMount() {
const { match: { params } } = this.props;
}
render() {
return (
<div>
<div className="container body">
<div className="main_container">
<Header />
<SideNav routeparams={this.props}/>
</div>
</div>
</div>
);
}
}
export default AppComp;
Sidenav.jsx
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom'
import '../../css/sidenav.css';
class SideNav extends Component {
render() {
console.log(this.props.routeparams);
return (
<div className="col-md-3 left_col">
<div className="left_col">
<div className="clearfix"></div>
<div id="sidebar-menu">
<div className="menu">
<ul className="nav side-menu">
<li>
<NavLink to="/app/home/dashboard">Home</span></NavLink>
<ul>
<li className="current-page">
<NavLink to="/app/home/dashboard" activeClassName="current">Dashboard</NavLink>
</li>
<li>
<NavLink to="/app/home/contact" activeClassName="current">Contact</NavLink>
</li>
<li>
<NavLink to="/app/home/account" activeClassName="current">Account</NavLink>
</li>
<li>
<NavLink to="/app/home/career" activeClassName="current">Career</NavLink>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
);
}
}
export default SideNav;
I have two issue :
this.props.routeparams in sidenav logged twice which means sidenav rendered twice . this is happening after adding routing . Also this.props.routeparams match path is always /app, which I think because sidenav is a child component of app component. How can I fix this ? I want to get current route path in sidenav.
activeClassName="current" gets applied to correct navlink but the css style gets reflected only if I click somewhere in the page. Seems so strange. I can resolve that issue if I get current match.path at sidenav component then I will do it custom way without activeClassName.
Any help would be greatly appreciated.

React Nested Routes throwing error - Meteor

Trying to setup a simple global layout (App), and have the path /apply render within App.
I keep getting the warning:
You should not use <Route component> and <Route children> in the same route; <Route children> will be ignored
Which I can tell 100% applies to the situation, but Google yielded no relevant answers/solutions to my problem.
Routes.jsx
import React from 'react';
import { render } from "react-dom";
import { Router, Route, IndexRoute } from "react-router";
import createBrowserHistory from "history/createBrowserHistory";
const history = createBrowserHistory();
// route components
import App from "./App.jsx";
import ApplyPage from "./pages/ApplyPage.jsx";
export const renderRoutes = () => (
<Router history={history}>
<Route path="/" component={App}>
<Route path="apply" component={ApplyPage}/>
</Route>
</Router>
);
App.jsx
import React, { Component } from 'react'
import TopBar from "./components/TopBar.jsx"
import LeftMenuContainer from "./components/LeftMenuContainer.jsx"
import LivePurchases from "./components/LivePurchases.jsx"
export default class App extends Component {
render() {
console.log(this.props);
return (
<div className="App">
<div className="flexWrapperGlobal">
<TopBar/>
<div className="contentContainer">
<LeftMenuContainer/>
<div className="bodyContainer">
<LivePurchases/>
<div className="siteContentContainer">
{this.props.children}
</div>
</div>
</div>
</div>
</div>
)
}
}
ApplyPage.jsx
import React, { Component } from 'react'
export default class ApplyPage extends Component {
render() {
return (
<div className="applyContainer">
<div className="applySubContainer">
<div className="applyBlock">
<h4>Seller Application</h4>
<form>
<h5>Roblox Account</h5>
<input type="text" placeholder="Username"/>
<h5>Selling Experience</h5>
<textarea type="text" placeholder="Selling Experience"/>
<h5>Extra Information</h5>
<textarea type="text" placeholder="Extra Information"/>
</form>
<a className="btn">Send</a>
</div>
</div>
</div>
)
}
}
I ran into this same issue today, found the solution here: Nested Routes in v4
<App>
<Route ....... />
<Route ....... />
</App>
This worked for me.
Found the answer, in case anyone's ran into the same examples.
You now nest the routes into your rendered top-level object, in my case App.
So you have to move <Route path="/apply" component={ApplyPage} /> to App.jsx, like this:
render() {
return (
<div className="App">
<div className="flexWrapperGlobal">
<TopBar/>
<div className="contentContainer">
<LeftMenuContainer/>
<div className="bodyContainer">
<LivePurchases/>
<div className="siteContentContainer">
<Route path="/apply" component={ApplyPage} />
</div>
</div>
</div>
</div>
</div>
)
}

Resources