I Single page rich application (SPA)
Understanding of single page rich application:
- The English of single page rich application is single page application, abbreviated as SPA;
- The whole Web application actually has only one page. When the URL changes, it will not request new static resources from the server;
- Instead, JavaScript monitors the changes of URLs and renders new pages according to different URLs;
How can I apply URL s and rendered pages? Front end routing
- The front-end route maintains the mapping relationship between the URL and the rendered page;
- Routing can be based on different URL s, and finally let our framework (such as Vue, React and Angular) render different components;
- Finally, what we see on the page is actually rendered component pages;
II Principle of front-end routing
How does front-end routing map URL and content?
- Listen for URL changes.
- principle
- When changing the URL, it does not cause the page to refresh
- When we hear that the URL changes, we can judge the current URL by ourselves and decide what kind of content to render.
There are two ways to change the URL without causing the page to refresh:
- Change the URL through the hash of the URL;
- Modify the URL through the history mode in HTML5;
2. hash of URL
- The hash of the URL, that is, the anchor (#), essentially changes the window href attribute of location;
- We can assign location Hash to change the href, but the page does not refresh;
- The href of the a element will be added directly after the original url
//html part <div id="app"> <a href="#/Home "> Home Page</a> <a href="#/About "> about</a> <div class="page"></div> </div> //script part <script> const page=document.querySelector('.page') window.addEventListener('hashchange',()=>{ //Monitor hash changes console.log('Change',location.hash); //location.hash get the current hash switch (location.hash) { case '#/home': page.innerHTML='about' break; case '#/about': page.innerHTML='home page' break; default: page.innerHTML='' break; } }) </script>
be careful:
- The advantage of hash is better compatibility, which can run in the old version of IE;
- But the defect is that there is a #, which doesn't seem to be a real path;
3. HTML5 History
The history interface is a new addition to HTML5. It has l six modes to change the URL without refreshing the page:
- replaceState: replace the original path;
- pushState: use the new path;
- popState: fallback of path;
- go: change the path forward or backward;
- forword: change the path forward;
- back: change the path backward;
<div id="app"> <a href="home">home page</a> //The default behavior of the a element is to jump to a new page <a href="/about">about</a> <div class="page"></div> <script> const page=document.querySelector('.page') const as=document.getElementsByTagName('a') for(let a of as){ a.addEventListener('click',(e)=>{ e.preventDefault(); //Block the default behavior of the a element const href=a.getAttribute('href') //Get the free attribute of a element // console.log('a element is clicked '); // history.pushState({},'','abc') / / the third parameter is the new path to jump history.pushState({},'',href) //If the third attribute is' abc ', it will jump under the original path //If '/ abc' is passed in, it will jump to a new path, not under the original path //A path refers to something behind a port urlChange() }) } //When you perform the return operation, you still come to urlchange window.addEventListener('popstate',urlChange) //Monitor url changes function urlChange(){ console.log(location.pathname);//location.pathname is the current path, //Equivalent to the href above switch (location.pathname) { //A path refers to something behind a port case '/home': page.innerHTML='about' break; case '/about': page.innerHTML='home page' break; default: page.innerHTML='' break; } } </script> </div>
//18 lines
III react-router
The available routing Library of the React project is the React router, which is also officially supported. It is also divided into:
React router core components
The react router DOM is applied to the browser side routing Library (used alone, including the core part of the react router)
React router native is applied to the routing at the native end
1. Basic use of router
To install the react Router:
- Installing react router DOM will automatically help us install the dependencies of react router;
yarn add react-router-dom
The main API of react router is some components provided to us:
(1)BrowserRouter and HashRouter
- It includes the monitoring of path change, and will pass the corresponding path to the sub components;
- BrowserRouter or HashRouter package components
- BrowserRouter uses history mode;
- HashRouter uses hash mode;
(2)Link and NavLink:
- Usually, the path jump uses the Link component, which will eventually be rendered as an a element;
- NavLink adds some style attributes on the basis of Link;
- To attribute: the most important attribute in Link, which is used to set the path to jump to;
(3)Route:
- Route is used for path matching;
- By default, the matching is fuzzy matching. As long as the previous matching arrives, it will jump to this page
- Path attribute: used to set the matching path;
- Component attribute: set the component to be rendered after matching to the path;
- Exact: accurate matching. Only when the exact matching reaches the completely consistent path can the corresponding components be rendered;
- If Route is placed in front of link, this component will be rendered on link. The location of house viewing is not fixed
//Import first import { HashRouter, Link, Route } from 'react-router-dom' export default class App extends PureComponent { render() { return ( <div> <HashRouter> <Link to='/' >home page</Link> <Link to='/about' >about</Link> <Route exact path='/' component={Home}/> <Route path='/about' component={About}/> </HashRouter> </div> ) } }
2. Use of navlink
Requirement: when the path is selected, the corresponding a element turns red
At this time, we need to use the NavLink component to replace the link component. NavLink has the free attribute, which is no different from other links
- activeStyle: the style when active (matching);
- activeClassName: class added when active;
- exact: whether it matches accurately;
<NavLink exact to='/' activeStyle={{color:'red'}}>home page</NavLink> <NavLink to='/about' activeStyle={{color:'red'}}>about</NavLink>
However, we will find that when about or profile is selected, the first one will also turn red:
- The reason is that the / path also matches / about or / profile;
- At this time, we can add the exact attribute to the first NavLink;
Default activeClassName:
- In fact, when the default matching is successful, NavLink will add a dynamic active class;
- So we can also write styles directly
a.active { color: red; }
Of course, if you are worried that this class will be used in other places and there will be a cascade of styles, you can also customize the class
<NavLink exact to="/" activeClassName="link-active">home page</NavLink> <NavLink to="/about" activeClassName="link-active">about</NavLink> <NavLink to="/profile" activeClassName="link-active">my</NavLink>
3. Function of switch
Default routing rule: fuzzy matching
- When we match a certain path, we will find some problems;
- For example, when the / about path is matched, the /: userid is also matched, and the last NoMatch component is always matched;
The reason is that by default, the components corresponding to the Route to which the path is matched in the react Route will be rendered;
However, in actual development, we often hope to have an exclusive idea:
- As long as the first one is matched, the latter one should not continue to match;
- At this time, we can use Switch to wrap all routes;
4. Redirect
Redirect is used for route redirection. When this component appears, it will jump to the corresponding to path:
That is, we open a website by default, and he directly jumps to another website without our click
The previous link or navlink will not jump. It must go through one of our interactions
Here is a case of using this:
- The User jumps to the User interface;
- However, there is an isLogin in the User interface to record whether the User logs in:
- true: displays the name of the user;
- false: redirect directly to the login interface;
App.js defines the Route corresponding to the Login page in advance:
<Switch> ...other Route <Route path="/login" component={Login} /> <Route component={NoMatch} /> </Switch>
In user Write the corresponding logic code in JS:
import React, { PureComponent } from 'react' import { Redirect } from 'react-router-dom'; export default class User extends PureComponent { constructor(props) { super(props); this.state = { isLogin: false } } render() { return this.state.isLogin ? ( <div> <h2>User</h2> <h2>user name: coderwhy</h2> </div> ): <Redirect to="/login"/> } }
IV Advanced use of react router
1. Route nesting
In development, there is a nested relationship between routes.
Here, we assume that there are multiple page contents in the about page:
import React, { PureComponent } from 'react' import { HashRouter, NavLink, Route, Switch } from 'react-router-dom' import About1 from './About1' import About2 from './About2' import About3 from './About3' export default class about extends PureComponent { render() { return ( <div> <NavLink exact to='/about' activeStyle={{color:'green'}}>recommend</NavLink> <NavLink to='/about/about2' activeStyle={{color:'green'}}>singer</NavLink> <NavLink to='/about/about3' activeStyle={{color:'green'}}>artist</NavLink> <Switch> <Route exact path='/about' component={About1}/> <Route path='/about/about2' component={About2}/> <Route path='/about/about3' component={About3}/> </Switch> </div> ) } }
- Whether Route or NavLink, it is recommended to add exact to the first one
- Note the characteristics of Switch. Under the sub route of about, if the first one does not add exact, the page will always match path = '/ about', and the page will not change
2. Manual jump
At present, the jump we realize is mainly through Link or NavLink. In fact, we can also jump through JavaScript code.
But there is a premise for jumping through JavaScript code: you must get the history object.
How can I get the object of history? Two ways
- Method 1: if the component jumps directly through the route, you can directly obtain the history, location and match objects;
This method can only be used in the sub navigation when the BrowserRouter or HashRouter is used in the primary navigation
Because ordinary components do not have history, location and match objects, router provides these objects
export default class about extends PureComponent { render() { return ( <div> <NavLink exact to='/about' activeStyle={{color:'green'}}>recommend</NavLink> <NavLink to='/about/about2' activeStyle={{color:'green'}}>singer</NavLink> <NavLink to='/about/about3' activeStyle={{color:'green'}}>artist</NavLink> <button onClick={e=>{this.shop()}}>Product list</button> <Switch> <Route exact path='/about' component={About1}/> <Route path='/about/about2' component={About2}/> <Route path='/about/about3' component={About3}/> <Route path='/about/about3' component={About3}/> <Route path='/about/about4' component={About3}/> </Switch> </div> ) } shop(){ this.props.history.push('/about/about4'); } }
- Method 2: if the component is an ordinary rendering component, you cannot directly obtain history, location and match objects;
If it is in the first level navigation, the above method has no effect
So what should ordinary components do if they also want to get the corresponding object properties?
- We have learned about high-level components before. You can add the desired attributes to the components;
- React router also adds relevant attributes to our components through high-level components;
If we want to get the history object in the App component, we must meet the following two conditions:
- App components must be wrapped in Router components;
- App components are wrapped with withRouter high-level components;
index.js code is modified as follows:
ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById('root') );
App.js code is modified as follows:
import { Route, Switch, NavLink, withRouter } from 'react-router-dom'; ...Omit other import codes class App extends PureComponent { render() { console.log(this.props.history); return ( <div> ...Other codes <button onClick={e => this.pushToProfile()}>my</button> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/profile" component={Profile} /> <Route path="/:userid" component={User} /> <Route component={NoMatch} /> </Switch> </div> ) } pushToProfile() { this.props.history.push("/profile"); } } export default withRouter(App);
3. Transfer parameters
There are three ways to pass parameters:
- Dynamic routing mode;
- search pass parameters;
- to pass in the object;
(1) Dynamic routing mode
The concept of dynamic routing means that the path in the route is not fixed:
If you directly write to = '/ about', the route is fixed
- For example, the path of / Detail corresponds to a component Detail;
- If we write the path as / detail/:id during Route matching, then / detail/abc and / detail/123 can be matched to the Route and displayed; Many to one relationship
- This matching rule is called dynamic routing;
In general, using dynamic routing can pass parameters for the route.
//id to jump const id='abc'; //Finally, jump to / about6/abc <NavLink to={`/about6/:${id}`} activeStyle={{color:'red'}}>about</NavLink> //Define Route <Route path='/about6/:id' component={About6}/> //Fixed writing
<div> ...other Link <NavLink to="/detail/abc123">details</NavLink> <Switch> ... other Route <Route path="/detail/:id" component={Detail}/> <Route component={NoMatch} /> </Switch> </div>
About6.js code is as follows:
We can get the id directly from the match object;
We do not use withRouter here because About6 itself is a jump through routing;
The reason why the id is obtained on the About6 page is that different contents can be displayed according to different IDs
import React, { PureComponent } from 'react' export default class About6 extends PureComponent { render() { const match=this.props.match //Get the match of the current route console.log(match); console.log(match.params.id); //The id is saved in match Params object return ( <div> <h2>About6 Dynamic routing:{match.params.id}</h2> </div> ) } }
(2)search pass parameters
NavLink:
- We added some query parameters to the jump path;
<NavLink to={`/about7?name=coderwhy&age=18`} activeStyle={{color:'red'}}>Detail 2</NavLink> <Route path='/about7' component={About7}/>
How to get it in About7?
- It is required in search 7;
import React, { PureComponent } from 'react' export default class About7 extends PureComponent { render() { console.log(this.props.location); return ( <div>to Transfer parameters:{this.props.location.search}</div> ) } }
- Note: this search has not been parsed and needs to be parsed by ourselves; Therefore, it is not recommended to pass parameters in this way
(3)to incoming object
to can pass in an object directly
<NavLink to={{ pathname: "/detail2", //This attribute must be written, which is the page to jump to query: {name: "kobe", age: 30}, state: {height: 1.98, address: "Los Angeles"}, search: "?apikey=123" }} activeStyle={{color:'red'}}>Detail 3</NavLink> <Route path='/about8' component={About8}/>
Get this object from the About8 page
import React, { PureComponent } from 'react' export default class About8 extends PureComponent { render() { console.log(this.props.location); return ( <div> About8 page to Transfer parameters </div> ) } }
V react-router-config
At present, all our Route definitions are completed by directly using the Route component and adding attributes.
However, this method will make routing very chaotic. We hope to put all routing configurations in one place for centralized management:
- At this time, you can use react router config;
Install react router config: yarn add react router config
Create a new route in the src directory
Common router / index JS file:
import Home from "../pages/home"; import About, { AboutMessage, AboutProduct } from "../pages/about"; import Profile from "../pages/profile"; import Login from "../pages/login"; import User from "../pages/user"; import Detail from "../pages/detail"; import Detail2 from "../pages/detail2"; import NoMatch from "../pages/nomatch"; const routes = [ { path: "/", //Page to jump to exact: true, //It is suggested that whether it is navigation or sub navigation, the first one should add this attribute to solve the fuzzy matching problem component: Home //Components to be displayed after jump }, { path: "/about", component: About, routes: [ //Equivalent to sub navigation under about { path: "/about", exact: true, component: AboutProduct }, { path: "/about/message", component: AboutMessage }, ] }, { path: "/profile", component: Profile }, { path: "/login", component: Login }, { path: "/user", component: User }, { path: "/detail/:id", component: Detail }, { path: "/detail2", component: Detail2 }, { component: NoMatch } ]; export default routes;
Replace the previous Switch configuration with the function provided in react router config:
import {renderRoutes} from 'react-route-config' import routes from './router/index' //Change the Switch directly to {renderRoutes(routes)} {/* <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/profile" component={Profile} /> <Route path="/user" component={User} /> <Route path="/login" component={Login} /> <Route path="/detail/:id" component={Detail}/> <Route path="/detail2" component={Detail2}/> <Route component={NoMatch} /> </Switch> */}
When clicking on a navigation, the color changes, but the content does not change, be sure to consider exact
If there is sub navigation under About navigation, it is the same as above
//1. Start with about Import in JS page import {renderRoutes} from 'react-route-config' //Replace the original Switch with //However, it must be noted that sub navigation is not directly passed into routes //routes is the total route //It should be routes under about navigation //Get the whole big navigation this in this page props. routes //Get this sub navigation this props. routes. routes renderRoutes(this.props.routes.routes) //Note the addition of exact in the first path
In fact, a matchRoutes auxiliary function is also provided in react router config:
matchRoutes(routes, pathname) passes in a routing object array to obtain all matching paths;
const routes = matchRoutes(this.props.route.routes, "/about"); console.log(routes);