I'm trying to build my first website with react, and I've had a lot of trouble with navigation. I'm using react-router and for some reason my tag is changing the url at the top of the page, but not rendering the proper component.
Here is my navbar.jsx:
import React, { Component } from "react";
import { Link, BrowserRouter } from "react-router-dom";
class Navbar extends Component {
render() {
return (
<BrowserRouter>
<div>
<ul>
<li><Link to={"/test"}>Test</Link></li>
</ul>
</div>
</BrowserRouter>
)
}
}
export default Navbar;
Here is test.jsx:
import React, { Component } from "react";
class Test extends Component {
state = {};
render() {
return (
<div>
<h1>Test</h1>
</div>
);
}
}
export default Test;
Does anyone know why this is changing the url(as expected), but not rendering test.jsx?
You need to use Route to render component for different routes.
import React, { Component } from 'react';
import { Link, BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import Test from './import-path-of-test-component';
class Navbar extends Component {
render() {
return (
<BrowserRouter>
<div>
<ul>
<li>
<Link to={'/test'}>Test</Link>
</li>
</ul>
<Switch>
<Route exact path="/test" component={Test} />
</Switch>
</div>
</BrowserRouter>
);
}
}
export default Navbar;
Related
I'm using React Router 4 in a TypeScript app where I have a React.Component that's used within a React.FunctionalComponent. I need to be able to navigate programmatically to a particular route from within the React.Component, but I can't seem to figure out how to pass the router down to the child component so that I can call this.props.history.push(). What complicates matters is that I'm using TypeScript, too.
Here's a code sandbox with a working demo of my component layout: https://codesandbox.io/s/react-programmatic-routing-xebpg
And now, the components:
app.tsx:
import * as React from 'react';
import { HashRouter } from 'react-router-dom';
import Header from './header';
import Footer from './footer';
import AppRouter from './app-router';
export default class App extends React.PureComponent {
public render() {
return (
<HashRouter>
<Header />
<AppRouter />
<Footer />
</HashRouter>
);
}
}
header.tsx:
import * as React from 'react';
import Navbar from 'react-bootstrap/Navbar';
import Nav from 'react-bootstrap/Nav';
import { NavLink } from 'react-router-dom';
export default class Header extends React.PureComponent<any> {
public render() {
return (
<Navbar>
<Nav.Link as={NavLink} exact to="/home">
Home
</Nav.Link>{' '}
<Nav.Link as={NavLink} to="/customers">
Customers
</Nav.Link>
</Navbar>
);
}
}
app-router.tsx:
import * as React from 'react';
import { Switch, Route } from 'react-router-dom';
import Home from './pages/home';
import Customers from './pages/customers';
const AppRouter: React.FC = () => {
return (
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/home" component={Home} />
<Route path="/customers" component={Customers} />
</Switch>
</div>
);
};
export default AppRouter;
pages/customers.tsx:
import * as React from 'react';
import MyFakeGrid from './customers-grid';
const Customers: React.FC = () => {
return (
<div>
<p>This is the customers page</p>
<MyFakeGrid />
</div>
);
};
export default Customers;
pages/customers-grid.tsx:
import * as React from 'react';
import { NavLink } from 'react-router-dom';
export default class MyFakeGrid extends React.Component {
public render() {
return (
<div style={{ borderColor: 'lightgray', borderStyle: 'solid' }}>
<p>
I need to be able to route programmatically from this
component
</p>
<p>
but I can't just use a NavLink like 'Home' (below), I have
to be able to navigate from within a method
</p>
<NavLink to="/home">Home</NavLink>
</div>
);
}
}
pages/home.tsx:
import * as React from 'react';
const Home: React.FC = () => {
return (
<div>
<p>This is the home page</p>
</div>
);
};
export default Home;
I've recently started learning React and I don't want to re-write my class-based components as functional components, which have become quite detailed/useful, especially not given React's gradual adoption strategy.
Base on React-router training, You can get access to the history object's properties and the closest 's match via the withRouter higher-order component. withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.
For example, you can re-write Customer component as blow:
import * as React from 'react';
import MyFakeGrid from './customers-grid';
import { withRouter } from "react-router";
const Customers: React.FC = () => {
return (
<div>
<p>This is the customers page</p>
<MyFakeGrid />
</div>
);
};
export default withRouter(Customers);
now you access to the history and other parameter as i said, and you can easily navigate between routes.
I am rookie to ReactJS and recently start learning. I've created 2 components home and ContactList using TSX. I am using React-Router to change route.
App.JS
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Header } from "./Grid/header";
import { Footer } from "./Grid/footer";
import { Menulink } from './Grid/Menulinks';
import { Home } from './Grid/Home';
import { ContactList } from './Grid/ContactList';
class App extends Component {
render() {
return (
<div>
<Header title="This is Header">
</Header>
<Menulink></Menulink>
<Router>
<switch>
<Route exact path="/" component={Home} />
<Route path="/contact" component={ContactList} />
</switch>
</Router>
<Footer></Footer>
</div>
)
}
}
export default App;
Menulink.tsx:
import * as React from 'react';
import { Link, BrowserRouter as Router } from "react-router-dom";
export class Menulink extends React.Component {
render() {
return (
<Router>
<switch>
<Link to="/">Home </Link> |
<Link to="/contact">Contact List</Link>
</switch>
</Router>
)
}
}
Issue is, when I click on link, URL change, but component is not
getting replace. is it because I've written links and route both in
different files?
First, you need to have one Router instance
Second, MenuLink needs to be rendered as a Child of Router
Third, import Switch from react-router-dom
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import { Header } from "./Grid/header";
import { Footer } from "./Grid/footer";
import { Menulink } from './Grid/Menulinks';
import { Home } from './Grid/Home';
import { ContactList } from './Grid/ContactList';
class App extends Component {
render() {
return (
<div>
<Header title="This is Header">
</Header>
<Router>
<Route component={Menulink} />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/contact" component={ContactList} />
</Switch>
</Router>
<Footer></Footer>
</div>
)
}
}
export default App;
import * as React from 'react';
import { Link, BrowserRouter as Router } from "react-router-dom";
export class Menulink extends React.Component {
render() {
return (
<React.Fragment>
<Link to="/">Home </Link> |
<Link to="/contact">Contact List</Link>
</React.Fragment>
)
}
}
This is because you have two different Router instances. You need only One router instance at the Top of the component heirarchy. Or at the very least..the heirarchy that you expect to be changing with URLs.
So if you put your <MenuLink /> under the <Router> that is defining the routes, your routing will work fine.
I have a homepage with a link to a form, like this:
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Route,
NavLink,
Redirect,
Switch,
withRouter
} from "react-router-dom";
import addHand from './Forms/addHand'
export class Home extends Component {
render() {
return (
<div>
<Router>
<div>
<NavLink to= '/hands/new'> Add a new hand </NavLink>
<Route path= '/hands/new' component={addHand}/>
<h4> Search For Hands By Category </h4>
<h4> Search For Sessions By Category </h4>
<h4> Search For Tables By Category </h4>
</div>
</Router>
</div>
);
}
}
export default Home;
I also have a navbar with a link to go home from any page, like this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';
import unmountComponentAtNode from 'react-dom';
class NavBar extends Component {
render() {
return (
<div className="navbar">
<NavLink className="link"
to="/"
exact
>Home</NavLink>
</div>
);
}
};
export default NavBar;
If I go to the form, then change my mind and decide I want to go back to the homepage, the url changes when I press the navlink, but the form is still rendered on the homepage. I can keep going back and forth between routes, but the only way to get the form to unmount from the DOM is to refresh the page. What causes this behavior, and what can I do to fix it? I have experienced similar issues before in React but have never found the solution. Thanks!
Edit** I tried adding this to the navlink:
render() {
const refCallback = node => {
unmountComponentAtNode(node)
}
return (
<div className="navbar">
<NavLink className="link"
to="/"
exact
innerRef={refCallback}
>Home</NavLink>
</div>
);
}
};
as per the react router docs, but it gives me this error:
unmountComponentAtNode(...): Target container is not a DOM element.
Here is the code in app.js
import React, { Component } from 'react';
import './App.css';
import { Router, Route } from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import Home from './Components/Home'
import Navbar from './Components/Navbar';
import addHand from './Components/Forms/addHand';
export const history = createBrowserHistory();
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title-top">Hi Adam, welcome to your Personal
Poker Universe!</h1>
<h1 className="App-title-middle">Not Adam? GTFO!</h1>
<h1 className="App-title-bottom">Just Kidding, you can stay</h1>
</header>
<Router history= {history}>
<div>
<Navbar/>
<Route exact path='/' component= {Home} />
</div>
</Router>
</div>
);
}
}
export default App;
Define one Router in your App.js:
<Router history={history}>
<Switch>
<Route exact path="/" component={Home} />} />
<Route path="/hands/new" component={addHand} />
</Switch>
</Router>
then try navigating between routes it should work. Please Let me know if it doesn't work
router link mouseenter event is not working.when i put the cursor on router link it does not change the routes. my router link working properly but i want to working on mouseenter event. please suggest me some way how can i solve this problem
import React, { Component } from 'react';
import { browserHistory } from "react-router";
import createHistory from "history/createBrowserHistory";
import ToggleDisplay from 'react-toggle-display';
import './App.css';
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
import Example from './Example.js';
import About from "./About.js";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import PropTypes from "prop-types";
class App extends Component {
constructor(props) {
super(props);
this.onNavigateHome = this.onNavigateHome.bind(this);
}
onNavigateHome() {
this.props.history.push('/about');
}
render() {
return <div className="App">
<Router >
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about" onMouseEnter={this.onNavigateHome.bind(this)}>
About
</Link>
</li>
</ul>
<hr />
<Route exact path="/" component={Example} />
<Route path="/about" component={About} />
</div>
</Router>
<Example />
</div>;
}
}
export default App;
React Router's Link is designed to be a click event not a mouse enter event. You can do it another way around by using state change when you do a mouse enter. Following is a pseudo code.
changeState(){
if (!this.state.entered) {
// window.location.href='/newResource';
this.props.history.push('/about');
}
this.setState({ entered : !this.state.entered });
}
render() {
return (<Router>
<span role="link" onMouseEnter={this.changeState}>
Link
</span>
</Router>);
}
Im New to react.
Im trying to implement this into my react app.
https://github.com/trungdq88/react-router-page-transition/blob/master/EXAMPLES.md
Now i dont want it to show on my home page like the example but in my "MyStories" component when you navigate to that component . But it seems i did something wrong and now im recieving this error.
Uncaught Error: MyStories.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
heres my code.
import React from 'react';
import { Router, Route, browserHistory } from 'react-router';
import Layout from './components/Layout';
import Profile from './components/Profile';
import MyStories from './components/MyStories';
import NewStory from './components/NewStory';
import PageTransition from 'react-router-page-transition';
import DetailPage from './components/DetailPage';
class Root extends React.Component {
constructor(props){
super(props)
this.state = {
}
}
render() {
return(
<Router history={browserHistory}>
<Route path='/' component={Layout}>
<IndexRoute component={Layout} />
<Route path="/MyStories" component={MyStories}/>
<Route path="/profile" component={Profile}/>
<Route path="/NewStory" component={NewStory}/>
<Route path="/detail/:itemId" component={DetailPage} />
</Route>
<Route path="/detail/:itemId" component={DetailPage} />
</Router>
)
}
}
export default Root;
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { browserHistory } from 'react-router';
import Root from './Root';
let reactAppRender = (element) => {
ReactDOM.render(
<Root browserHistory={browserHistory}/>,
element
);
};
$(function() {
let reactApp = document.getElementById('app');
if (reactApp) {
reactAppRender(reactApp);
}
});
import React from 'react'
import { Link } from 'react-router';
export default React.createClass({
render() {
return
<div className="transition-item list-page">
{this.state.items.map(item => (
<Link
key={item.id}
className="list-item"
to={`/detail/${item.id}`}
>
<Item {...item} />
</Link>
))}
</div>
}
})
import React from 'react';
import { Link } from 'react-router';
import PageTransition from 'react-router-page-transition';
class Layout extends React.Component {
constructor(props){
super(props)
this.state = {
}
}
render() {
return(
<div>
<h1>Welcome </h1>
<ul role="nav">
<li><Link to='/'>HOME</Link></li>
<li><Link to="/profile">Profile</Link></li>
<li><Link to="/mystories">MyStories</Link></li>
<li><Link to="/newstory">NewStory</Link></li>
</ul>
<PageTransition>
{this.props.children}
</PageTransition>
</div>
)
}
}
export default Layout;
import React from 'react';
import { Link } from 'react-router';
export default class DetailPage extends React.Component {
render() {
return (
<div className="transition-item detail-page">
<Link to="/">Back</Link>
<h1>
Detail {this.props.params.itemId}
</h1>
</div>
);
}
}
The component above Layout has a render() method with a return in one line, but what you want to return starts in the line below it:
import React from 'react'
import { Link } from 'react-router';
export default React.createClass({
render() {
return
<div className="transition-item list-page">
{this.state.items.map(item => (
<Link
key={item.id}
className="list-item"
to={`/detail/${item.id}`}
>
<Item {...item} />
</Link>
))}
</div>
}
})
When this happens, wrap the JSX component in parenthesis:
import React from 'react'
import { Link } from 'react-router';
export default React.createClass({
render() {
return (
<div className="transition-item list-page">
{this.state.items.map(item => ( //Incidentally, you reference this.state here but your component has no state
<Link
key={item.id}
className="list-item"
to={`/detail/${item.id}`}
>
<Item {...item} />
</Link>
))}
</div>
)
}
})
You did this in the other components, you might have just missed this one.
For the future: if you get an error along the lines of Uncaught Error: MyStories.render(): A valid React element (or null) must be returned. look at return statement of the render method of the component that the error is mentioning (in this case, MyStories). Remember, for now you can only return JSX from the render method of a React component.