Understanding basics of reach router - javascript

I am trying to understand basics of reach router and have doubts on following code
import React from "react";
import { render } from "react-dom";
import Logo from "./Logo";
import { Router, Link } from "#reach/router";
let Home = () => (
<div>
<h1>Home</h1>
<nav>
<Link to="/">Home</Link> |{" "}
<Link to="/dashboard">Dashboard</Link>
</nav>
</div>
)
let Dash = () => <div>Dash</div>
render(<Router>
<Home path="/" />
<Dash path="dashboard" />
</Router>, document.getElementById("root"));
I know that this Router works as Switch from router 4, i.e., renders only one path inside router.
Now when I start the app initially I am inside Home, e.g. here
<div>
<h1>Home</h1>
<nav>
<Link to="/">Home</Link> |{" "}
<Link to="/dashboard">Dashboard</Link>
</nav>
</div>
At this moment it is my belief that Dashboard component hasn't been rendered anywhere. However, if I type dashboard in URL or click the above link it correctly takes me to Dashboard component.
My question is how does algorithm of resolving to Dashboard works in this case?
Does it "restart" the app and see that there was a component registered for "dashboard" route initially?
My point is because when I am at home location there is nothing on the page anymore that indicates that Dashboard component is registered under dashboard route, or I am wrong?

<Router>'s internal implementation uses history.listen() (https://github.com/reach/router/blob/master/src/index.js#L103) which in turn listens to native popstate events (https://developer.mozilla.org/en-US/docs/Web/Events/popstate). You can see it in action here.
It looks like your intuitions are indeed right. <Router> component is history-aware by listening to history changes. It re-renders routes as a result of internal setState calls.
I can recommend going though the source code if you'd like to know even more about implementation details.

Related

SideBar and Dashboard with React-Router

I want to connect my sidebar to dashboard. Everytime I click on an icon in the sidebar I want to sidebar to stays the same but dashboard to change. https://imgur.com/1hwNlNr I am having a problem with the rendering. When I click on the Sound Icon Sidebar does not stay as you can see https://imgur.com/YjLmhLh
import React from 'react'
import './SystemSidebar.css'
import SoundIcon from '#material-ui/icons/Computer';
import ComputerIcon from '#material-ui/icons/Computer';
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom';
import Sound from './Sound';
import Computer from './Computer;
const SystemSidebar=()=> {
return (
<div className='system'>
<div className="sidebar">
<Link to='Sound'><VolumeUpIcon /></Link>
<h4> Sound</h4>
<Link to='Computer'><ComputerIcon /></Link>
<h4> Computer</h4>
</div>
</div>
import React,{Component} from 'react'
import Sound from './Sound';
import Computer from './Computer';
import SystemSidebar from './SystemSidebar';
class MainSystem extends Component {
render(){
return (
<div className="MAIN">
<BrowserRouter>
<SystemSidebar />
<Switch>
<Route exact path="/" component={SystemSidebar} />
<Route exact path="/Sound" component={Sound}/>
<Route exact path="/Computer" component={Computer}/>
</Switch>
</BrowserRouter>
</div>
);
}
}
Did you post the code from two separate .js files into this code block? Your SystemSidebar function is missing some closing parenthesis/brackets and this code has multiple duplicate imports/incorrect paths if all this code lives in the same file.
Other than that, you're rendering SystemSidebar twice when at the root URL. You want a component for some type of home/welcome page at this route, not the sidebar:
<Route exact path="/" component={SystemSidebar} />
Please post complete code in separate code blocks if the code is in separate files.

React material-ui navigate another html page and render an initial component in it

I am designing a web site using material-ui (https://material-ui.com/). I have toolbar with buttons. As usual, I want to navigate another html page when I click one of the buttons and render an initial component for new html page. For example, from 'Main Page' (for now, its localhost:3000/) to 'About' page (localhost:3000/About).
I tried something similar to this,
import { Link } from 'react-router-dom';
function ListItemLink(props) {
const { icon, primary, to } = props;
const CustomLink = props => <Link to={'/About'} {...props} />;
return (
<Button component={CustomLink} /> About
);
}
https://github.com/mui-org/material-ui/issues/10955 but it did not work. I searched many other methods but none of them is doing what I want. In the picture below, I have 'About' and 'News' folders under public folder. Each of them has its own index.html file. And I also have 'index.js' under src folder.
By default, nmp starts index.html under 'public' folder and execute index.js for this html file.
I want to make this scenario when I route other folders with button click.
Is there any preferrable way to do this ?
Thanks.
I recommend reading the documentation for React Router.
https://reactrouter.com/web/guides/quick-start
In the code below, the Switch component is what is used to see what should be rendered based on the Route components under it.
You need this switch logic setup or your buttons won't do anything.
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
{/* A <Switch> looks through its children <Route>s and
renders the first one that matches the current URL. */}
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}

React router renders blank page after import

I am new to React and I am trying to create a sidebar having links to different pages or modules. I have everything modularized meaning, the sidebar Navigation is a separate module where I import all the linked classes and then use react-router-dom to redirect the paths. But somehow when redirecting, The response page is blank.
Navigation Module:
import React, { Component } from "react";
import { Route, Switch, Link } from "react-router-dom";
import Colors from "../../pages/Colors";
import Typography from "../../pages/Typography";
import Spaces from "../../pages/Spaces";
import Buttons from "../../pages/Buttons";
import Inputs from "../../pages/Inputs";
import Grid from "../../pages/Grid";
import "./style.css";
class Nav extends Component {
render() {
return (
<div className="nav">
<ul>
<li>
<Link to="/colors">Colors</Link>
</li>
<li>
<Link to="/typography">Typography</Link>
</li>
<li>
<Link to="/spaces">Spaces</Link>
</li>
<li>
<Link to="/buttons">Buttons</Link>
</li>
<li>
<Link to="/inputs">Inputs</Link>
</li>
<li>
<Link to="/grid">Grid</Link>
</li>
</ul>
<Switch>
<Route path="/colors" component={Colors} exact />
<Route path="/typography" component={Typography} exact />
<Route path="/spaces" component={Spaces} exact />
<Route path="/buttons" component={Buttons} exact />
<Route path="/inputs" component={Inputs} exact />
<Route path="/grid" component={Grid} exact />
</Switch>
</div>
);
}
}
export default Nav;
Now the link classes that I import here have just simple content right now like the following.
pages/Colors/index.js:
import React, { Component } from "react";
class Colors extends Component {
render() {
return (
<div>
<h1>Colors</h1>
</div>
);
}
}
export default Colors;
The main BrowserRouter is located in the App.js component from where the Sidebar component is called having Navigation component.
Now the thing is if I remove the BrowserRouter from App.js and put it in the Navigation module the routing works.
How come so?
Which pattern is the correct one?
When you work with React-router and React-router-dom, make sure the Router component is the top most parent.
You can try again by:
Move all Router, Switch into App.js.
Inside Sidebar component, just render links, neither Switch nor Route component.
It will work.
Similar to the answer from Shina, who covers it pretty well, just a few more comments. Keeping your React-Router and switch in your App.jsx file is relatively standard. Since App is the parent component, the Router and Switch will only be rendered once, while keeping the router in Nav.jsx would force the Switch re-rendered with each route. But keeping the Switch wrapped in the Router component should solve your issues here.

React Router Still Renders Previous Page after Routing to New Component

I am making a landing page for my site, which will have 3 components - header, main and footer, only for the landing page. The header component is just a nav bar with a logo on the left and sign in button on the right.
When the sign in button is clicked, I render a login route using the router but the problem is the previous components of Landing page (Header, Main and Landing) are also rendered with the new routed Login component.
Here's my App.js file where Landing is inserted.
import React, {Component} from 'react';
import Landing from './components/Landing/Landing';
class App extends Component {
render() {
return (
<div className="App">
<Landing/>
</div>
);
}
}
export default App;
and in Landing component I have this setup:
import React, {Component} from 'react';
import Header from './Header';
import Main from './Main';
import Footer from './Footer'
class Landing extends Component {
render() {
return (
<div className="container__landing">
<Header/>
<Main/>
<Footer/>
</div>
);
}
}
export default Landing;
Here's my header component, for brevity I have left out the other two components:
import React, {Component} from 'react';
import {BrowserRouter as Router, Link} from 'react-router-dom';
import {Route, Switch} from 'react-router';
import Login from '../auth/Login';
class Header extends Component {
render() {
return (
<Router>
<header className="header">
<div className="header__nav">
<p>STRONG LIVE</p>
<button className="sign_in">
<Link to="/login">
Sign In
</Link>
</button>
</div>
<Route exact path="/login" component={Login}/>
</header>
</Router>
)
}
}
export default Header;
The login component is rendered but it's placed inside the landing component along with the header and other present components.
I want the login page to be stand-alone and without the header, which is currently above it.
I have seen some tutorial where they have used the props.history.push('/path) but in React Dev Tools, none of my components have these props.
How do I switch components on button click? Thank you.
When the URL will match the path property of your <Route> component, a.k.a. when you'll be on the /login page, React router will render your <Login> component at the place in your component tree where the corresponding <Route> is.
The problem is that your <Router>, and more specifically your login <Route> are inside the <Landing> component.
If you want the login page to be rendered without header, you should place both the <Landing> and <Login> components inside a <Route>, next to each other. Then, render them conditionally using React Router's <Switch>component :
A <Switch> will iterate over all of its children elements and only render the first one that matches the current location. (see the documentation for details)
Here's an (untested) example :
class App extends Component {
render() {
return (
<div className="App">
<Router>
<Switch>
{/* Render the login component alone if we're on /login */}
<Route exact path="/login" component={Login} />
{/* Otherwise, render the Landing component */}
<Route component={Landing} />
</Switch>
</Router>
</div>
);
}
}

Routes are not matched by react-router(-redux)

I'm stuck creating a single page app using react, redux, react-router and react-redux-router bindings.
The route http://localhost:3001/register is simply not matched by the router and Cannot GET /register is returned to the browser because the server obviously doesn't know the route. I'm relatively new to the react-redux stack and may be missing something pretty basic.
Edit: The IndexRoute is working and is displaying the Home-Component inside the App-Compontent.
Edit2: I'm not using server side rendering and am developing using the webpack-dev-server.
But here are the related code-snippets so far:
entry.js
const store = createStore(
reducer, //from reducers.js
applyMiddleware(routerMiddleware(browserHistory))
);
const history = syncHistoryWithStore(browserHistory, store);
render(
<Provider store={store}>
<Router history={history} routes={routes} /> //routes from routes.js
</Provider>,
document.getElementById('app')
);
reducers.js
const rootReducer = combineReducers({
RegisterForm,
routing: routerReducer //provided by react-router-redux
});
export default rootReducer;
routes.js
const routes = (
<Route path='/' component={App}>
<IndexRoute component={Home} />
<Route name='register' path='register' component={RegisterForm} />
</Route>
);
export default routes;
Navigation.jsx (rendered inside App.jsx)
import React from 'react';
import {Link} from 'react-router';
export default class Navigation extends React.Component {
render() {
return (
<div className="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header className="mdl-layout__header">
<div className="mdl-layout__header-row">
<span className="mdl-layout-title">there!</span>
<div className="mdl-layout-spacer"></div>
<nav className="mdl-navigation mdl-layout--large-screen-only">
<Link className="mdl-navigation__link" to="/">Home</Link>
<Link className="mdl-navigation__link" to="register">Register</Link>
</nav>
</div>
</header>
<div className="mdl-layout__drawer">
<span className="mdl-layout-title">there!</span>
<nav className="mdl-navigation">
<Link className="mdl-navigation__link" to="/">Home</Link>
<Link className="mdl-navigation__link" to="register">Register</Link>
</nav>
</div>
<main className="mdl-layout__content">
<div className="page-content">
{this.props.children}
</div>
</main>
</div>
);
}
}
Maybe it is obvious to someone, what I am missing here. If you need more of the code please let me know.
As you say, the problem is that your backend does not know how to handle requests to /register. The solution is to tell your backend to return the react application (same as requests to /) on such requests.
If you are developing with pure webpack-dev-server I'm not 100% sure what's the best way to do this, but you can take a look at the answer here which will probably work: Stating directive templateUrl relative to root
You can use hashHistory instead of browserHistory. It's written in react-router's documentation.
Of course, you will need to configure the Link's to props so it will redirect properly according to the needs of hashHistory. Later on, when you are back using browserHistory, you need to reconfigure those links again.

Categories