ReactRouter-Implementierung ReactRouter ist die Kernkomponente von React . Er wird hauptsächlich als Routing-Manager von React verwendet, um UI und URL synchronisiert zu halten. Er verfügt über eine einfache API und leistungsstarke Funktionen wie das Laden des Codepuffers, dynamische Routenanpassung und die Einrichtung einer korrekten Standortübergangsverarbeitung. beschreiben React Router basiert auf history Verlaufsobjekt. Kurz gesagt, ein history kann Änderungen in der Adressleiste des Browsers überwachen und die URL in ein location zerlegen. router verwendet es dann, um die Route abzugleichen und rendert schließlich die entsprechende Komponente korrekt. Es gibt drei häufig verwendete Formen history : Browser History , Hash History und Memory History . Browserverlauf Browser History ist der empfohlene history für Anwendungen, die React Router verwenden. Er verwendet pushState , replaceState und andere API History im Browser sowie popstate -Ereignisse, um URL zu verarbeiten. Er kann eine echte URL wie https://www.example.com/path erstellen. Wenn die Seite springt, muss die Seite nicht neu geladen werden und es wird natürlich keine Anforderung an den Server gestellt. Natürlich erfordert history weiterhin Unterstützung der Back-End-Konfiguration, um Anforderungen von anderen als der Startseite sowie vom Back-End beim Aktualisieren zurückgegebene Ressourcen zu unterstützen. Da es sich bei der Anwendung um eine einseitige Client-Anwendung handelt, wird bei einer falschen Konfiguration des Back-Ends 404 zurückgegeben, wenn der Benutzer direkt im Browser URL zugreift. Daher muss auf dem Server eine Kandidatenressource hinzugefügt werden, um alle Situationen abzudecken. Wenn URL keiner statischen Ressource entspricht, sollte sie dieselbe Anwendungsabhängigkeitsseite index.html zurückgeben, beispielsweise die Konfiguration unter Nginx .
Standort / {
Versuchen Sie, Dateien $uri $uri/ /index.html zu versuchen.
} Hash-Verlauf Das Hash -Symbol # wurde ursprünglich verwendet, um den Speicherort einer Webseite in URL anzugeben. Beispielsweise stellt https://www.example.com/index.html#print den print von index.html von example dar. Nachdem der Browser diese URL gelesen hat, wird print automatisch in den sichtbaren Bereich gescrollt. Der Ankerpunkt wird normalerweise mithilfe name Attributs des <a> -Tags oder id -Attributs des <div> -Tags angegeben. Die Ankerposition kann über die Eigenschaft window.location.hash gelesen werden, und für die Änderung Hash kann hashchange hinzugefügt werden. Jedes Mal, wenn Hash geändert wird, wird dem Zugriffsverlauf des Browsers ein Eintrag hinzugefügt. Außerdem wird Hash , obwohl er in URL erscheint, nicht in die HTTP Anforderung aufgenommen, d. h. # und die darauf folgenden Zeichen werden nicht an den Server gesendet, um Ressourcen oder Daten anzufordern. Er wird verwendet, um die Aktionen des Browsers zu steuern, und hat keine Auswirkungen auf den Server. Daher wird die Seite durch die Änderung Hash nicht neu geladen. Die Rolle von ReactRouter besteht darin, Komponenten dynamisch zu laden und zu zerstören, indem URL geändert und die Seitenansicht aktualisiert wird, ohne die Seite erneut anzufordern. Einfach ausgedrückt, obwohl sich die Adresse in der Adressleiste geändert hat, handelt es sich nicht um eine brandneue Seite, sondern einige Teile der vorherigen Seite wurden geändert. Dies ist auch das Merkmal der SPA -Einzelseitenanwendung. Alle ihre Aktivitäten sind auf eine Web beschränkt. Nicht verzögert geladene Seiten laden nur die entsprechenden HTML , JavaScript und CSS Dateien, wenn die Web initialisiert wird. Sobald die Seite geladen ist, lädt SPA die Seite nicht neu und springt auch nicht, sondern verwendet JavaScript , um HTML dynamisch umzuwandeln. Der Standard- Hash Modus besteht darin, das Routing über Anker zu implementieren und die Anzeige und das Ausblenden von Komponenten zu steuern, um Interaktionen ähnlich wie Seitensprünge zu erreichen. Speicherverlauf Memory History wird nicht in der Adressleiste bedient oder gelesen, was erklärt, wie das Server-Rendering implementiert wird. Es eignet sich auch sehr gut zum Testen und für andere Rendering-Umgebungen wie React Native . Ein Unterschied zu den anderen beiden History besteht darin, dass wir sie erstellen müssen, was das Testen erleichtert.
const history = createMemoryHistory(Speicherort); erreichen Lassen Sie uns einen sehr einfachen Browser History und Hash History implementieren. Da die pushState -Methode von H5 nicht im lokalen Dateiprotokoll file:// ausgeführt werden kann, müssen Sie für die Ausführung eine http:// Umgebung erstellen. Sie können webpack , Nginx , Apache usw. verwenden. Zurück zum Routing Browser History : Dank pushState() , replaceState() und anderen von H5 bereitgestellten Methoden und Ereignissen wie popstate können Sie history implementieren, ohne die Seite zu aktualisieren. Diese Methoden können auch den Routingpfad ändern, führen aber keine Seitensprünge aus. Wenn das Backend nicht gut konfiguriert ist, wird die Seite natürlich nach der Anpassung des Routings aktualisiert und 404 Eingabeaufforderung angezeigt. Für den Hash History sind unsere Implementierungsideen ähnlich, hauptsächlich insofern, als wir keine H5 - API wie pushState verwenden und die Abhörereignisse unterschiedlich sind. Indem wir auf die Änderungen in seinem hashchange Ereignis hören, erhalten wir das entsprechende location.hash , um die entsprechende Ansicht zu aktualisieren.
<!-- Browserverlauf -->
<!DOCTYPE html>
<html lang="de">
<Kopf>
<meta charset="UTF-8">
<title>Router</title>
</Kopf>
<Text>
<ul>
<li><a href="/home" rel="external nofollow" >Startseite</a></li>
<li><a href="/über" rel="external nofollow" >über</a></li>
<div id="routeView"></div>
</ul>
</body>
<Skript>
Funktion Router() {
this.routeView = null; // Von der Komponente gehosteter Ansichtscontainer this.routes = Object.create(null); // definierte Routen }
// Route-Matching-Ereignis binden Router.prototype.route = function (path, callback) {
this.routes[Pfad] = () => this.routeView.innerHTML = callback() || "";
};
// InitializeRouter.prototype.init = Funktion(root, rootView) {
this.routeView = rootView; //Den Ansichtscontainer angeben this.refresh(); //Ansicht initialisieren und aktualisieren root.addEventListener("click", (e) => { //Ereignisdelegierung an root
wenn (e.target.nodeName === "A") {
e.preventDefault();
history.pushState(null, "", e.target.getAttribute("href"));
this.refresh(); // Auslöser zum Aktualisieren der Ansicht}
})
// Achten Sie beim Zurück- und Vorwärtsgehen auf Benutzerklicks // pushState und replaceState lösen das Popstate-Ereignis nicht aus window.addEventListener("popstate", this.refresh.bind(this), false);
};
// Aktualisieren Sie viewRouter.prototype.refresh = function () {
let path = Standort.Pfadname;
console.log("aktualisieren", Pfad);
wenn(diese.routen[Pfad]) diese.routen[Pfad]();
sonst this.routeView.innerHTML = "";
};
Fenster.Router = neuer Router();
Router.route("/home", Funktion() {
Heimkehr";
});
Router.route("/über", Funktion () {
gib "ungefähr" zurück;
});
Router.init(Dokument, Dokument.getElementById("routeView"));
</Skript>
</html>
<!-- Hash-Verlauf -->
<!DOCTYPE html>
<html lang="de">
<Kopf>
<meta charset="UTF-8">
<title>Router</title>
</Kopf>
<Text>
<ul>
<li><a href="#/home" rel="external nofollow" >Startseite</a></li>
<li><a href="#/about" rel="external nofollow" >über</a></li>
<div id="routeView"></div>
</ul>
</body>
<Skript>
Funktion Router() {
this.routeView = null; // Von der Komponente gehosteter Ansichtscontainer this.routes = Object.create(null); // definierte Routen }
// Route-Matching-Ereignis binden Router.prototype.route = function (path, callback) {
this.routes[Pfad] = () => this.routeView.innerHTML = callback() || "";
};
// InitializeRouter.prototype.init = Funktion(root, rootView) {
this.routeView = rootView; //Den Ansichtscontainer angeben this.refresh(); //Initialisierungstrigger //Auf Hashchange-Ereignisse warten, um sie zu aktualisieren window.addEventListener("hashchange", this.refresh.bind(this), false);
};
// Aktualisieren Sie viewRouter.prototype.refresh = function () {
sei hash = Standort.hash;
console.log("aktualisieren", Hash);
wenn(diese.routen[hash]) diese.routen[hash]();
sonst this.routeView.innerHTML = "";
};
Fenster.Router = neuer Router();
Router.route("#/home", Funktion() {
Heimkehr";
});
Router.route("#/about", Funktion () {
gib "ungefähr" zurück;
});
Router.init(Dokument, Dokument.getElementById("routeView"));
</Skript>
</html> analysieren- Werfen wir einen Blick auf die Implementierung von
ReactRouter . commit id lautet eef79d5 TAG ist 4.4.0 . Zuvor müssen wir history Verlaufsbibliothek verstehen. history history ist eine erweiterte Version von window.history , auf die sich ReactRouter stützt. Die wichtigsten verwendeten Objekte sind das match Objekt, das das Ergebnis der Übereinstimmung zwischen der aktuellen URL und path darstellt. location Objekt ist eine Ableitung history Verlaufsbibliothek, die auf window.location basiert. -
ReactRouter teilt das Routing in mehrere Pakete auf: react-router ist für die allgemeine Routing-Logik verantwortlich, react-router-dom ist für das Browser-Routing-Management verantwortlich react-router-native ist für das react-native -Routing-Management verantwortlich.
- Nehmen wir als Beispiel
BrowserRouter -Komponente. In react-router-dom ist BrowserRouter eine übergeordnete Komponente, die intern ein globales history erstellt, das Änderungen in der gesamten Route überwachen und history als props an Router Komponente von react-router übergeben kann. Router Komponente übergibt dann die Attribute dieses history als context an die untergeordnete Komponente.
// packages\react-router-dom\modules\HashRouter.js Zeile 10
Klasse BrowserRouter erweitert React.Component {
Verlauf = Verlauf erstellen(this.props);
rendern() {
gibt <Routerverlauf={this.history} untergeordnete Elemente={this.props.children} /> zurück;
}
} Als nächstes gehen wir zur Router Komponente. Router Komponente erstellt eine React Context Umgebung, die mit Hilfe von context context an Route übergibt, was auch erklärt, warum Router außerhalb aller Route liegen sollte. In componentWillMount von Router wird history.listen hinzugefügt, das Änderungen im Routing überwachen und Callback-Ereignisse ausführen kann, die hier setState auslösen. Wenn setState aufgerufen wird, d. h. jedes Mal, wenn sich die Route ändert -> das Rückrufereignis des Router der obersten Ebene wird ausgelöst -> Router führt setState aus -> übergibt nextContext . Zu diesem Zeitpunkt enthält context den neuesten location -> die folgende Route erhält den neuen nextContext , um zu bestimmen, ob gerendert werden soll.
// Zeile packages\react-router\modules\Router.js Zeile 10
Klasse Router erweitert React.Component {
static computeRootMatch(Pfadname) {
return { Pfad: "/", URL: "/", Parameter: {}, isExact: Pfadname === "/" };
}
Konstruktor(Requisiten) {
super(Requisiten);
dieser.Zustand = {
Standort: props.history.location
};
// Das ist ein bisschen ein Hack. Wir müssen anfangen, auf den Standort zu hören
// Änderungen hier im Konstruktor, falls es <Redirect>s gibt
// beim ersten Rendern. Wenn ja, werden sie ersetzt/gepusht, wenn
// Sie nehmen zu und da cDM bei Kindern vor den Eltern ausbricht, können wir
// Holen Sie sich einen neuen Standort, bevor der <Router> gemountet wird.
this._isMounted = falsch;
this._pendingLocation = null;
wenn (!props.staticContext) {
this.unlisten = props.history.listen(Standort => {
wenn (this._isMounted) {
this.setState({ Standort });
} anders {
this._pendingLocation = Standort;
}
});
}
}
componentDidMount() {
dies._isMounted = wahr;
wenn (this._pendingLocation) {
this.setState({ Standort: this._pendingLocation });
}
}
componentWillUnmount() {
wenn (dies.unlisten) dies.unlisten();
}
rendern() {
zurückkehren (
<RouterContext.Provider
Kinder = {this.props.children || null}
Wert={{
Geschichte: this.props.history,
Standort: dieser.Bundesstaat.Standort,
Übereinstimmung: Router.computeRootMatch(dieser.Status.Standort.Pfadname),
statischer Kontext: this.props.staticContext
}}
/>
);
}
} Bei der Verwendung verwenden wir Router zum Verschachteln Route , sodass wir nun zur Route Komponente kommen. Die Rolle von Route besteht darin, die Route abzugleichen und sie zum Rendern an die Komponenten props zu übergeben. Route akzeptiert den vom Router der höheren Ebene übergebenen context . history im Router überwacht die Routenänderungen der gesamten Seite. Wenn die Seite springt, löst history das Listening-Ereignis aus und Router übergibt nextContext nach unten, wodurch props und context von Route aktualisiert werden, um zu bestimmen, ob path der aktuellen Route location übereinstimmt. Wenn dies der Fall ist, wird es gerendert, andernfalls wird es nicht gerendert. Die Grundlage für die Übereinstimmung ist die Funktion computeMatch , die weiter unten analysiert wird. Hier müssen Sie nur wissen, dass match null ist, wenn der Abgleich fehlschlägt. Wenn der Abgleich erfolgreich ist, wird das Ergebnis match als Teil props verwendet und in render an die zu rendernde Komponente übergeben. Route akzeptiert drei Arten von render props : <Route component> , <Route render> und <Route children> . Zu diesem Zeitpunkt ist zu beachten, dass, wenn die übergebene component eine Inline-Funktion ist, React da props.component jedes Mal neu erstellt wird, denkt, dass während diff eine neue Komponente hinzugekommen ist, und die alte Komponente unmount und re-mount . Zu diesem Zeitpunkt müssen Sie render verwenden. Ohne eine Schicht von umschlossenen component ist der Elementtyp nach der Erweiterung von render jedes Mal derselbe, sodass weder re-mount erfolgt noch children erneut re-mount werden.
// \packages\react-router\modules\Route.js Zeile 17
Klasse Route erweitert React.Component {
rendern() {
zurückkehren (
<RouterContext.Verbraucher>
{Kontext => {
invariant(context, "Sie sollten <Route> nicht außerhalb eines <Router> verwenden");
const Standort = this.props.location || Kontext.Standort;
const match = this.props.computedMatch
? this.props.computedMatch // <Switch> hat das Match bereits für uns berechnet
: dieser.Eigenschaften.Pfad
? matchPath(Standort.Pfadname, diese.Eigenschaften)
: Kontext.Übereinstimmung;
const props = { ...Kontext, Ort, Übereinstimmung };
let { untergeordnete Elemente, Komponente, Render} = this.props;
// Preact verwendet ein leeres Array als untergeordnetes Element von
// Standard, also verwenden Sie in diesem Fall null.
wenn (Array.isArray(Kinder) && Kinder.Länge === 0) {
Kinder = null;
}
wenn (Typ der untergeordneten Elemente === "Funktion") {
Kinder = Kinder(Requisiten);
// ...
}
zurückkehren (
<RouterContext.Provider-Wert={props}>
{Kinder && !isEmptyChildren(Kinder)
? Kinder
: Requisiten.Match
? Komponente
React.createElement(Komponente, Requisiten)
: render
? render(Requisiten)
: null
: null}
</RouterContext.Provider>
);
}}
</RouterContext.Consumer>
);
}
} Tatsächlich ist das Tag, das wir wahrscheinlich am häufigsten schreiben, das Link -Tag. Schauen wir uns also noch einmal die <Link> -Komponente an. Wir können sehen Link letztendlich ein a Tag erstellt, um das Element zu umschließen, zu dem gesprungen werden soll. Im handleClick -Ereignis dieses a Tags verhindert preventDefault den Standardsprung. Daher hat href hier tatsächlich keine praktische Auswirkung, kann aber dennoch URL der Seite angeben, zu der gesprungen werden soll, und hat eine bessere html Semantik. In handleClick preventDefault für Klicks verwendet, die nicht preventDefault sind, Linksklicks, keine _blank Sprünge und kein Gedrückthalten anderer Funktionstasten, und dann in history push . Dies ist auch das zuvor erwähnte, dass Routenwechsel und Seitensprung nicht miteinander in Beziehung stehen. ReactRouter ruft pushState des HTML5 history durch push history Verlaufsbibliothek in Link auf, aber dies ändert nur die Route und sonst nichts. Beim listen im Router wird auf Änderungen in der Route geachtet, und dann werden props und nextContext Kontext über context aktualisiert, damit die zugrunde liegende Route erneut übereinstimmt und die Aktualisierung des Teils abgeschlossen wird, der gerendert werden muss.
// Pakete\react-router-dom\modules\Link.js Zeile 14
Klasse Link erweitert React.Component {
handleClick(Ereignis, Verlauf) {
wenn (this.props.onClick) this.props.onClick(Ereignis);
Wenn (
!event.defaultPrevented && // onClick verhindert standardmäßig
event.button === 0 && // alles außer Linksklicks ignorieren
(!this.props.target || this.props.target === "_self") && // Browser mit „target=_blank“ usw. umgehen lassen.
!isModifiedEvent(event) // Klicks mit Modifikatortasten ignorieren
) {
event.preventDefault();
const-Methode = this.props.replace ? history.replace : history.push;
Methode(this.props.to);
}
}
rendern() {
const { innerRef, replace, to, ...rest } = this.props; // eslint-disable-line keine unbenutzten Variablen
zurückkehren (
<RouterContext.Verbraucher>
{Kontext => {
invariant(context, "Sie sollten <Link> nicht außerhalb eines <Routers> verwenden");
Konstantstandort =
typeof zu === "Zeichenfolge"
? createLocation(nach, null, null, Kontext.Standort)
: Zu;
const href = Standort? context.history.createHref(Standort): "";
zurückkehren (
<a
{...ausruhen}
bei Klick = {Ereignis => this.handleClick(Ereignis, Kontext.Verlauf)}
href={href}
ref={innerRef}
/>
);
}}
</RouterContext.Consumer>
);
}
} Frage des Tages https://github.com/WindrunnerMax/EveryDay siehe https://zhuanlan.zhihu.com/p/44548552 https://github.com/fi3ework/blog/issues/21 https://juejin.cn/post/6844903661672333326 https://juejin.cn/post/6844904094772002823 https://juejin.cn/post/6844903878568181768 https://segmentfault.com/a/1190000014294604 https://github.com/youngwind/blog/issues/109 http://react-guide.github.io/react-router-cn/docs/guides/basics/Histories.html Dies ist das Ende dieses Artikels über die Implementierungsmethode von ReactRouter. Weitere Informationen zur Implementierung von ReactRouter finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen! Das könnte Sie auch interessieren:- Detaillierte Verwendung von React.Children
- Anwendungsbeispiele für React Hooks
- Tiefgreifendes Verständnis der Kernprinzipien von React Native (Bridge of React Native)
- React+Koa-Beispiel zur Implementierung des Datei-Uploads
- Beispielcode für die Entwicklung einer H5-Formularseite basierend auf React-Hooks und der Konfiguration der Zarm-Komponentenbibliothek
- Das Umschalten zwischen React-Antd-Tabs führt zu wiederholter Aktualisierung von Unterkomponenten
- ReactJs-Grundlagen-Tutorial - Essential Edition
- Detaillierte Erklärung zur Verwendung von React.cloneElement
|