Make Switch component respect URL fragments with React Router? - react-router

How can I do hash routing with React Router?
This works fine:
return (
<div>
<div>
<Link to="/one">One</Link>
<Link to="/two">Two</Link>
</div>
<Switch>
<Route exact path="/one" component={One} />
<Route exact path="/two" component={Two} />
<Route component={Three} />
</Switch>
</div>
);
However this always renders component Three:
return (
<div>
<div>
<Link to="/#one">One</Link>
<Link to="/#two">Two</Link>
</div>
<Switch>
<Route exact path="/#one" component={One} />
<Route exact path="/#two" component={Two} />
<Route component={Three} />
</Switch>
</div>
);
Do I need the hash router for this? I don't find the docs very clear:
https://reacttraining.com/react-router/web/api/HashRouter

Component Three is rendered because that's the default one whenever there is no routing point that matches a given URL.
You're right, you should use HashRouter provided by the react-router-dom package. Based on the documentation, the appropriate configuration should be something similar to this in your case:
import { HashRouter } from 'react-router-dom';
<HashRouter basename="/" hashType="noslash">
<App />
</HashRouter>
Thereby the root path is changed to /#.
To stick to your example:
<div>
<div>
// http://localhost:3000/#one
<Link to="/#one">One</Link> // This can be either /one or /#one
<Link to="/#two">Two</Link>
</div>
<Switch>
<Route exact path="/one" component={One} />
<Route exact path="/two" component={Two} />
<Route component={Three} />
</Switch>
</div>
Unfortunately, the path prop should be the same as before.
The documentation also contains an example of how the router creates the href links in this situation.

Related

What's the best way to change a global component based on the current route?

I'm building a website with React and I would like my navbar to have a different background color depending on the current route. My App.js looks like this:
class App extends React.Component {
render() {
return (
<Router>
<div className="App">
<div className="Navbar" >
<Navbar />
</div>
<div className="Content">
<Route path="/" exact render={() => <LandingPage />} />
<Route path="/about" exact render={() => <AboutPage />} />
<Route path="/contact" exact render={() => <ContactPage />} />
</div>
</div>
</Router>
);
}
}
Suppose I want a transparent background on the Home ("/") page, but a solid color everywhere else, what is the best way to go about changing the background property in <Navbar />'s CSS to achieve what I want?
Suppose I stored the CSS properties I'd like to change in this.state, and then call a function to change these whenever there is a route change?
You can use context api for changing the background color of any of your components. So, you just need to define a context value based on the different urls.

Working around the Auth0 sample requirement to add history to react router

When following the official Auth0 React SDK Quickstart guide, the code indicates the following:
function App() {
return (
<div className="App">
{/* Don't forget to include the history module */}
<Router history={history}>
<header>
<NavBar />
</header>
<Switch>
<Route path="/" exact />
<Route path="/profile" component={Profile} />
</Switch>
</Router>
</div>
);
}
However, when trying to provide history to React Router, it gives me back an error! So why does Auth0 require that there, and is there a way around it?

In react router 4, how does one negate a route / path using regex?

Say i have a route switch statement like the following:
render () {
<pre>
<Switch>
<Route path="/foo" render={render}>
<Route path="/bar" render={renderBar}>
<Route path="/" render={renderHome}>
{/* How do i express everything except the home page ?*/}
<Route render={renderFourOhFour}>
</Switch>
</pre>
}
How do i write a route that excludes everything except the home page given the above example? Do i just write a regex? If so i've tried something like
path={^(?!.*(home))}
with the regex react router v4 tester: https://pshrmn.github.io/route-tester/#/
You can use the render method on the Route, which gets passed the location as a prop. So:
<Route render={({location}) => {
return location.pathname !== '/' ? <p>Not home</p> : ''
}} />
1) It will be visible everywhere except /home
<Route path={/\/(?!home)/} component={Component} />
2) Everywhere except /
<Route path={/^.{2,}$/} component={Component} />
In react router 4, there isn't a explicit way to. I had redesign it in a way that the switch statement as a stack or queue.
It'll match the first few route components as the first choices and you'll have to place the last item as the default.
For example:
<Route path="/" exact component={Home}/>
<Route path="/will-match" component={WillMatch}/>
<Route component={NoMatch} />

How to route to sub directories from, when there is no trailing slash?

I am using react-router v4
Let's assume I am at the following location
http://localhost:3000/articles
I want this location to have a react router Link element, which points to
http://localhost:3000/articles/new
first try:
<Link to="new" />
points at
http://localhost:3000/new
second try:
<Link to="/new" />
from any location points at
http://localhost:3000/new
third try:
<Link to="new" />
from
http://localhost:3000/articles/ /* notice the slash at the end */
points at
http://localhost:3000/articles/new
success, but I need it to work from:
http://localhost:3000/articles
You should point the Link to /articles/new
<Link to="/articles/new" />
You Router should be similar to this:
const App = () => (
<Router>
<div className="wrapper">
<Route path="/" exact component={Home} />
<Route path="/articles" component={Articles} />
<Route path="/articles/new" component={New} />
</div>
</Router>
);
Note: Configuring your Router as the example will render both components (Articles and New). If you want to reder only the New, you should add the property exact to the parent component.
<Route path="/articles" exact component={Articles} />

React JS component with nested navigation

I've been having some trouble with the following. I've tried for a few hours to find some help through searching, but have come up empty handed. It could be that I don't know the name of what I'm trying to do, but I figured I'd ask here.
I've been learning React for about a month. Currently I'm trying to create a component which has it's own navigation bar and displays it's content based on which link in the component's navigation bar is clicked.
I have a Navigation bar for the entire website, using React Router, and I've tried nesting the component's route in the Route for the page I want it displayed, but when I click on a link within said component, instead of simply having the content displayed within that component, I'm navigated to a new page (in this case: localhost3000/#/project1). That new page displays the entire component, with the correct content. However, I want to avoid navigating to a new page.
Here's a pic of what I want to do.
Here's some of the code I've got so far. (I've omitted the imports and anything else unnecessary.
My index.js
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={OtherPage}></IndexRoute>
<Route path="Project_Page" component={ProjectPage} />
<Route component={ProjectsComponent}>
<Route path="project1" component={Project1} />
<Route path="project2" coponent={Project2} />
<Route path="project3" coponent={Project3} />
</Route>
<Route path="Another_Page" component={AnotherPage}></Route>
</Route>
</Router>
,
document.getElementById('root')
);
My ProjectPage.js
export default class ProjectPage extends Component{
render(){
return(
<div>
<ProjectsComponent />
</div>
);
}
}
My ProjectsComponent.js
export default class ProjectsComponent extends Component{
render(){
return(
<div>
<ProjectsNav /> // this is the navbar for my projects component
<div>
{this.props.children}
</div>
</div>
);
}
}
My ProjectsNav.js
export default class ProjectsNav extends Component{
render(){
return(
<div>
<Link to="Project1" className="btn btn-primary">Project 1</Link>
<Link to="Project2" className="btn btn-primary">Project 2</Link>
<Link to="Project3" className="btn btn-primary">Project 3</Link>
</div>
);
}
}
Finally
My Project1.js project2 && project3 are pretty much the same thing.
export default class Project1 extends Component{
render(){
return(
<div className="project">
Hello from Project 1
</div>
);
}
}
I'm sorry if this is something that's already been covered. If it has, please feel free to point me in the right direction. That's really all I need.
Thank you so much for your help.
ProjectsComponent component is not required, Try these components:
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={OtherPage}></IndexRoute>
<Route path="Project_Page" component={ProjectPage}>
//<Route component={ProjectsComponent}>
<IndexRoute path="Project_Page/Project1" component={Project1} />
<Route path="Project_Page/Project2" coponent={Project2} />
<Route path="Project_Page/Project3" coponent={Project3} />
</Route>
<Route path="Another_Page" component={AnotherPage}></Route>
</Route>
</Router>
,
document.getElementById('root')
);
export default class ProjectPage extends Component{
render(){
return(
<div>
<ProjectsNav />
<div>
{this.props.children}
</div>
</div>
);
}
}
export default class ProjectsNav extends Component{
render(){
return(
<div>
<Link to="Project_Page/Project1" className="btn btn-primary">Project 1</Link>
<Link to="Project_Page/Project2" className="btn btn-primary">Project 2</Link>
<Link to="Project_Page/Project3" className="btn btn-primary">Project 3</Link>
</div>
);
}
}
Let me know if u face any issue or want any help.