If you want to understand React Router, you should first understand history. To be more precise, history, a package that provides core functions for React Router. It easily adds location-based navigation to the project on the client, a feature that is critical to single page applications.
npm install --save history
There are three types of history, namely browser, hash, and memory. The history package provides the creation method of each history.
import { createBrowserHistory, createHashHistory, createMemoryHistory } from 'history'
If you use React Router, it will automatically create history objects for you, so you don't need to interact directly with history. However, it is still important to understand different types of history so that you can decide which one to use in the project.
What is history?
No matter what history you create, you end up with an object that has almost the same properties and methods.
location
The most important property in the history object is location. The location object reflects the "location" of the current application. It contains the properties derived from the 'URL', pathname, search[Note 1], hash.
In addition, each location has a key that is associated with and unique to it. 'key' is used to identify a specific location and stores data to a specific location.
Finally, the location can have a status associated with it. This is some fixed data and does not exist in the URL.
{ pathname: '/here', search: '?key=value', hash: '#extra-information', state: { modal: true }, key: 'abc123' }
When creating a history object, the location needs to be initialized. This process is also different for different types of history. For example, browser history parses the current URL.
One location controls all?
Admittedly, we can only access the current location, and history objects continuously track a set of locations. It is precisely because of the ability to add locations and be able to access any location in an array that history is called "history". If history can only record the current location, it should be called "present".
In addition to a set of locations, history also saves an index value to point to the current corresponding location.
For memory history, they are defined directly. For browser history and hash history, arrays and indexes are controlled by the browser and cannot be accessed directly [Note 2].
navigation method
It can be said that the navigation method is the finishing touch of the history system with location attributes. navigation allows you to change the current location.
Push method
The push method enables you to jump to the new location. When adding a new location after the current location, any 'future' location will be cleared (the location after the current location formed by the back button).
By default, when you click <Link>, the method is called to navigate.
({ pathname: '/new-place' })
replace
The replace method is similar to push, but it does not add location, but replaces the position on the current index. 'Future' location will not be cleared.
Use replace when redirecting. This is also the method used in the React Router's <Redirect> component.
For example, when you navigate to page 2 by clicking the link button on page 1, page 2 may redirect to page 3. If using the push method, clicking the Put Back button will return from page 3 to page 2 (there is a potential possibility to redirect to page 3). If you use the replace method, you will directly return to page 1 from page 3.
({ pathname: '/go-here-instead' })
go, go, go
Finally, there are three methods with ‘go’, namely goBack, goForward and go.
goBack returns a layer of page. In fact, it is to subtract the index value of history by 1.
()
goForward is opposite to goBack. Go to the front page. This only takes effect when the 'future' location is available, i.e. when the user clicks the back button.
()
go is a powerful method and includes the functions of goForward and goBack. If a negative number is passed, it will retreat, and if a positive number is passed, it will forward.
(-3)
monitor!
In the observer mode, history will issue notifications when the location changes. Each history object has a listen method that accepts a function as an argument. This function will be added to the listener function array stored in history. When the location changes (such as the code calls the history method or the user clicks the browser button), the history object will call all listener methods. This allows you to set up code updates when location changes.
const youAreHere = ('youAreHere') (function(location) { = })
The router component of React Router will subscribe to the history object so that it can be re-rendered when the location changes.
Linking things together
Each history has a createHref method, which uses a location object and outputs a URL.
Internally, history is navigated through location objects. However, like the anchor element (a), it does not know the history package, nor what the location object is. In order to enable the generated HTML to be able to navigate without history. We have to generate a true URL.
const location = { pathname: '/one-fish', search: '?two=fish', hash: '#red-fish-blue-fish' } const url = (location) const link = ('a') = url // <a href='/one-fish?two=fish#red-fish-blue-fish'></a>
The above covers the basic history API. Although there are other properties and methods that have not been introduced, the above method can be used to understand how history objects work.
Combine together
There are still differences between different types of history, which requires you to consider choosing a history that suits your project.
Between the three of them, any use case should be covered.
In the browser
browser history and hash history are both used in browser environments. They interact with the history and location's web APIs, so the current location is the same as what is shown in the browser's address bar.
const browserHistory = createBrowserHistory() const hashHistory = createHashHistory()
The biggest difference between them is the way you create locations from URLs. browser history uses the full URL [Note 3], while hash history only uses the part of the URL after the first hash.
// Provide the following URLurl = '/this/is/the/path?key=value#hash' // The location object created by browser history:{ pathname: '/this/is/the/path', search: '?key=value', hash: '#hash' } //The location object created by hash history:{ pathname: 'hash', search: '', hash: '' }
Using hash
Why do you need hash history? Theoretically, when you navigate to a URL, the server must have a corresponding file corresponding to it. For dynamic services, the request file does not need to be real. Instead, the server checks the requested URL and decides the returned HTML.
However, the static file service can directly return files that exist on disk. The most dynamic thing a static service can do is return files from the directory when the URL forms a directory.
Due to this limitation of static file service, the easiest solution [Note 4] is to use only a real location on the server to return the user's acquisition requirements. Of course, having only one location means that your application has only one URL, so history cannot be used. To solve this problem, hash history uses the hash part of the URL to read and write location.
// If using static resource service, all three URLs will be from// /my-site/get the same data/my-site#/one /my-site#/two // However, due to the use of hash history, the locations of the three in the application are different.// Because the location depends on the hash part of the URL{ pathname: '/one' } { pathname: '/two' }
Even though hash history works well, it is considered possible to be hacked because it relies on keeping all path information in the hash of the URL. Therefore, consider using the website when there is no dynamic service.
memory: cache all history
The best experience with memory location is that you can use it wherever you can use JavaScript.
A simple example you can use it in unit tests by running Node. This allows you to test your code without relying on the browser to run.
What's even more awesome is that memory history can be used in the app. In react-router-native in react-native app, react-router-native uses memory history to implement location-based navigation.
You can use memory history in your browser if you prefer. (Although this way you will lose the ability to interact with the address bar).
The biggest difference between this memory history and the other two types of history is that it maintains its own location. After creating memory history, you can pass in information for initialization. This state is the index of a location array and the current location [Note 5]. This is different from the other two types of history, which rely on the browser to store this location array.
const history = createMemoryHistory({ initialEntries: ['/', '/next', '/last'], initialIndex: 0 })
Using history instead of you to deal with relatively cumbersome and error-prone is an effective method.
No matter what type of history you choose, they are extremely easy to use and have powerful capabilities for navigation and loop-based rendering.
Comments
[1] The search attribute is a string rather than a parsed object. Because most string parsing packages vary in usage. So history leaves the option to the developer instead of forcing some kind of string parsing package. If you want to know more, here are some popular ones:query-string,querystringWith nativeURLSearchParams
[2] This is due to security limitations. In the browser, history's location array not only contains accessed location information. Open browsing will leak the user's browser history information, so it is not open to access.
[3] m By default, browser history creates a location object whose path name is the URL full path name. Of course, you can give history a basic name so that this part of the path name will be ignored.
const history = createBrowserHistory({ basename: '/path' }) // The given path url: /path/here// The history object will be created as follows{ pathname: '/here', ... }
[4] In theory, each valid URL in the application can be made to return the same HTML file. Although this is a matter of matter, if all URLs are static, a large number of redundant files will be generated. However, it is not feasible to use a large number of parameters to match a large number of possible addresses with any address.
[5] If the initialization location array and index of memory history are not provided, the following default value will be generated:
entries = [{ pathname: '/' }] index = 0
This is good enough for most applications, but writing history in advance is still a very useful way to restore content.
This is the end of this article about React Router’s brief discussion on history. For more related React Router history, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!