One-page apps you should know about

What is a single page app?

Single Page Web Application (SPA) is an application with only one Web page. Is a Web application that loads a single HTML page and dynamically updates that page as the user interacts with the application. React and Vue are the mainstream front-end frameworks for building single-page applications.

Single-page vs. multi-page apps

contrast Single page application Multi-page application
composition A shell page is composed of multiple page components (fragments) Multiple complete pages
Resources (CSS, js). Shareable and only need to be loaded in the shell Requests are made to the server as needed and resources are independent
For the first time to load The first screen loads slowly There’s not much difference in each load
The user experience Good user experience, content changes do not need to reload the entire page, the subsequent server pressure is small The page takes a long time to load
Animated transitions Can be implemented Unable to realize
Search Engine Optimization (SEO) Poor effect, can be rendered by SSR server, high cost The effect is good

Principle of SPA Single page Application (Role of routing)

By monitoring route changes, you can match the components corresponding to the route and map the components to the route. The framework effectively updates and renders components correctly when routing changes.

What you need to know about the HashRouter implementation

Here I introduce the implementation principle and process of HashRouter

There are three components of routing

The React Router has three components:

  1. Router (including HashRouter and BrowserRouter)

Hash and history modes of the corresponding route

  1. Route Matching Component (Route)

Control the display component corresponding to the path

  1. Navigation components (Link)

Route switchover, hop

Manual implementation process

Take a demo as an example

export default class App extends Component {
  render() {
    return (
      <HashRouter>
        <Route path="/home" component={Home}></Route>
        <Route path="/user" component={User}></Route>
      </HashRouter>
    )
  }
}
ReactDOM.render(<App />,
  document.getElementById('root'));Copy the code

Here the Route component gets the corresponding path and the component to be displayed, nested within the Router component.

HashRouter components

First we need to know some features of BOM

The BOM is a set of apis for operating browsers, and window is a top-level object in the BOM. We can use this.props to print some information mounted under the window, for example, digging gold

The implementation of a HashRouter relies on these apis, and we can retrieve our url value via window.location.href.

Of course you can just go through this? Wait, how does Route, a nested component of the HashRouter, get the URL path to match path?

The react-router uses the react.createcontext API introduced in React16.3

Context provides a way to pass data through the component tree

Can resolve parent components to child components, grandchildren… Pass value, provides a solution for nested data transfer for multiple components.

// We introduce the API with a context.js method import React from'react';
let { Provider, Consumer } = React.createContext()
export { Provider, Consumer }
Copy the code

The HashRouter acts as this producer, listening for hash changes through window.addeventListener (‘hashChange’,callback) and passing them on to its nested components.

The specific code is as follows:

import React, { Component } from 'react';
import { Provider } from './context'Class HashRouter extends Component {class HashRouter extends Component {constructor() {
    super()
    this.state = {
      location: {
        pathname: window.location.hash.slice(1) || '/'}} // Url path changes change locationcomponentDidMount() {
    window.location.hash = window.location.hash || '/'
    window.addEventListener('hashchange', () => { this.setState({ location: { ... this.state.location, pathname: window.location.hash.slice(1) ||'/'
        }
      }, () => console.log(this.state.location))
    })
  }
  render() {
    let value = {
      location: this.state.location
    }
    return( <Provider value={value}> { this.props.children } </Provider> ); }}export default HashRouter;
Copy the code

The Route component

The Route component acts as the consumer, receiving the URL path value passed by the HashRouter via a callback and matching the rendering component later

import React, { Component } from 'react';
import { Consumer } from './context'
const { pathToRegexp } = require("path-to-regexp");
class Route extends Component {
  render() {
    return (
      <Consumer>
        {
          state => {
            console.log(state)
            let {path, component: Component} = this.props
            let pathname = state.location.pathname
            let reg = pathToRegexp(path, [], {end: false}) // Check whether the current path contains pathNameif(pathname.match(reg)) {
              return <Component></Component>
            }
            returnnull } } </Consumer> ); }}export default Route;
Copy the code

Since the official implementation of regular expressions is relatively complex, I used the plug-in path-to-regexp to handle regular matching.

Effect:

conclusion

This time, the implementation process of HashRouter is simply simulated, and the implementation principle of React-Router is also understood. Finally, the learning process, focus on summary, joy in sharing, you can see the specific code of my Github welcome everyone to leave a message and I share 😀.