Livellamento con React: React Router

Questo tutorial è il primo di una serie in tre parti su React di Brad Westfall. Quando Brad mi ha lanciato questo, ha sottolineato che ci sono una buona quantità di tutorial su come iniziare in React, ma non tanto su dove andare da lì. Se sei nuovo di zecca per reagire, ti consiglio di guardare questo video introduttivo. Questa serie riprende dove le basi lasciano fuori.

Serie di articoli:

  1. Reagire Router (Tu sei qui!)
  2. Componenti contenitore
  3. Redux

Attenzione! Questo articolo è stato scritto pre-React Router 4, che è diventato una scelta più standard per il routing in React. C’è un nuovo articolo che copre React Router 4 qui si dovrebbe assolutamente leggere.

Quando stavo imparando, ho trovato molte guide per principianti (cioè 1, 2, 3, 4) che mostravano come creare singoli componenti e renderli al DOM. Hanno fatto un ottimo lavoro nell’insegnare le basi come JSX e props, ma ho faticato a capire come funziona React nel quadro più ampio, come un’applicazione a pagina singola (SPA) del mondo reale. Poiché questa serie copre molto materiale, non coprirà i concetti di principiante assoluto. Invece, inizierà con il presupposto che hai già capito come creare e renderizzare almeno un componente.

Per quello che vale, ecco alcune altre grandi guide che mirano ai principianti:

  • Reagire.js e come si adatta a tutto il resto?
  • Ripensare (Industria) le migliori pratiche
  • Reagire.js Introduzione Per le persone che sanno quanto basta jQuery per ottenere da

Codice serie

Questa serie viene fornito con un po ‘ di codice per giocare con GitHub. Per tutta la serie, costruiremo un centro BENESSERE di base incentrato su utenti e widget.

Per mantenere le cose semplici e brevi, gli esempi di questa serie inizieranno assumendo che React e React Router vengano recuperati da una CDN. Quindi non vedrai require() o import negli esempi immediati seguenti. Verso la fine di questo tutorial, però, introdurremo Webpack e Babel per le guide GitHub. A quel punto, è tutto ES6!

React-Router

React non è un framework, è una libreria. Pertanto, non risolve tutte le esigenze di un’applicazione. Fa un ottimo lavoro nella creazione di componenti e nella fornitura di un sistema per la gestione dello stato, ma la creazione di una SPA più complessa richiederà un cast di supporto. Il primo che vedremo è React Router.

Se hai usato un router front-end prima, molti di questi concetti saranno familiari. Ma a differenza di qualsiasi altro router che ho usato prima, React Router utilizza JSX, che potrebbe sembrare un po ‘ strano all’inizio.

Come primer, questo è come rendere un singolo componente:

var Home = React.createClass({ render: function() { return (<h1>Welcome to the Home Page</h1>); }});ReactDOM.render(( <Home />), document.getElementById('root'));

Ecco come il componente Home verrebbe reso con React Router:

...ReactDOM.render(( <Router> <Route path="/" component={Home} /> </Router>), document.getElementById('root'));

Si noti che <Router> e <Route> sono due cose diverse. Sono tecnicamente componenti React, ma in realtà non creano DOM da soli. Mentre può sembrare che lo stesso <Router> venga reso a 'root', in realtà stiamo solo definendo regole su come funziona la nostra applicazione. Andando avanti, vedrai spesso questo concetto: i componenti a volte esistono non per creare DOM stessi, ma per coordinare altri componenti che lo fanno.

Nell’esempio, <Route> definisce una regola in cui la visita alla home page / renderà il componente Homein 'root'.

Percorsi multipli

Nell’esempio precedente, il percorso singolo è molto semplice. Non ci dà molto valore dal momento che avevamo già la possibilità di rendere il componente Home senza che il router fosse coinvolto.

La potenza del router React arriva quando usiamo più percorsi per definire quale componente dovrebbe eseguire il rendering in base a quale percorso è attualmente attivo:

ReactDOM.render(( <Router> <Route path="/" component={Home} /> <Route path="/users" component={Users} /> <Route path="/widgets" component={Widgets} /> </Router>), document.getElementById('root'));

Ogni <Route> renderà il rispettivo componente quando il suo percorso corrisponde all’URL. Solo uno di questi tre componenti verrà reso in 'root' in un dato momento. Con questa strategia, montiamo il router al DOM 'root' una volta, quindi il router scambia i componenti dentro e fuori con le modifiche del percorso.

Vale anche la pena notare che il router cambierà rotta senza fare richieste al server, quindi immagina che ogni componente possa essere una pagina completamente nuova.

Layout riutilizzabile

Stiamo iniziando a vedere le umili origini di un’applicazione a pagina singola. Tuttavia, non risolve ancora i problemi del mondo reale. Certo, potremmo costruire i tre componenti per essere pagine HTML complete, ma per quanto riguarda il riutilizzo del codice? È probabile che questi tre componenti condividano risorse comuni come un’intestazione e una barra laterale, quindi come impediamo la ripetizione HTML in ciascun componente?

Immaginiamo che stavamo costruendo un’app web che assomigliava a questo mockup:

Un semplice sito web mockup.

Quando inizi a pensare a come questo mockup può essere suddiviso in sezioni riutilizzabili, potresti finire con questa idea:

Come si potrebbe suddividere il semplice mockup web in sezioni.

Pensare in termini di componenti e layout nidificabili ci consentirà di creare parti riutilizzabili.

Improvvisamente, il reparto arte consente di sapere che l’applicazione ha bisogno di una pagina per la ricerca di widget che assomiglia alla pagina per la ricerca degli utenti. Con l’elenco degli utenti e l’elenco dei widget che richiedono lo stesso “look” per la loro pagina di ricerca, l’idea di avere il layout di ricerca come componente separato ha ancora più senso ora:

Cerca i widget ora, al posto degli utenti, ma le sezioni padre rimangono le stesse.

Layout di ricerca può essere un modello genitore per tutti i tipi di pagine di ricerca ora. E mentre alcune pagine potrebbero aver bisogno di Layout di ricerca, altri possono utilizzare direttamente il layout principale senza di esso:

Un layout disaccoppiato.

Questa è una strategia comune e se hai usato qualsiasi sistema di template, probabilmente hai fatto qualcosa di molto simile. Ora lavoriamo sull’HTML. Per iniziare, faremo HTML statico senza considerare JavaScript:

<div> <!-- Main Layout --> <div class="app"> <header class="primary-header"><header> <aside class="primary-aside"></aside> <main> <!-- Search Layout --> <div class="search"> <header class="search-header"></header> <div class="results"> <!-- User List --> <ul class="user-list"> <li>Dan</li> <li>Ryan</li> <li>Michael</li> </ul> </div> <div class="search-footer pagination"></div> </div> </main> </div></div>

Ricorda, l’elemento 'root' sarà sempre presente poiché è l’unico elemento che il corpo HTML iniziale ha prima dell’avvio di JavaScript. La parola “root” è appropriata perché la nostra intera applicazione React verrà montata su di essa. Ma non c’è un” nome giusto ” o una convenzione per quello che lo chiami. Ho scelto “root”, quindi continueremo ad usarlo in tutti gli esempi. Fai attenzione che il montaggio direttamente sull’elemento <body> è altamente scoraggiato.

Dopo aver creato l’HTML statico, convertirlo in componenti React:

var MainLayout = React.createClass({ render: function() { // Note the `className` rather than `class` // `class` is a reserved word in JavaScript, so JSX uses `className` // Ultimately, it will render with a `class` in the DOM return ( <div className="app"> <header className="primary-header"><header> <aside className="primary-aside"></aside> <main> {this.props.children} </main> </div> ); }});var SearchLayout = React.createClass({ render: function() { return ( <div className="search"> <header className="search-header"></header> <div className="results"> {this.props.children} </div> <div className="search-footer pagination"></div> </div> ); }});var UserList = React.createClass({ render: function() { return ( <ul className="user-list"> <li>Dan</li> <li>Ryan</li> <li>Michael</li> </ul> ); }});

Non essere troppo distratto tra quello che sto chiamando “Layout” vs “Componente”. Tutti e tre questi sono componenti React. Ho appena scelto di chiamare due di loro “Layout” dal momento che è il ruolo che stanno eseguendo.

Alla fine useremo “percorsi nidificati” per posizionare UserList all’interno di SearchLayout, quindi all’interno di MainLayout. Ma prima, nota che quando UserList è posizionato all’interno del suo genitore SearchLayout, il genitore userà this.props.children per determinare la sua posizione. Tutti i componenti hanno this.props.children come prop, ma è solo quando i componenti sono annidati che il componente genitore ottiene questo prop riempito automaticamente da React. Per i componenti che non sono componenti padre, this.props.children sarà null.

Percorsi nidificati

Quindi, come facciamo a far nidificare questi componenti? Il router lo fa per noi quando nidifichiamo percorsi:

ReactDOM.render(( <Router> <Route component={MainLayout}> <Route component={SearchLayout}> <Route path="users" component={UserList} /> </Route> </Route> </Router>), document.getElementById('root'));

I componenti verranno nidificati in base al modo in cui il router annida i suoi percorsi. Quando l’utente visita il percorso /users, React Router posizionerà il componente UserList all’interno di SearchLayoute quindi entrambi all’interno di MainLayout. Il risultato finale della visita /users saranno i tre componenti nidificati posizionati all’interno di 'root'.

Si noti che non abbiamo una regola per quando l’utente visita il percorso della home page (/) o vuole cercare i widget. Quelli sono stati lasciati fuori per semplicità, ma mettiamoli con il nuovo router:

ReactDOM.render(( <Router> <Route component={MainLayout}> <Route path="/" component={Home} /> <Route component={SearchLayout}> <Route path="users" component={UserList} /> <Route path="widgets" component={WidgetList} /> </Route> </Route> </Router>), document.getElementById('root'));

Probabilmente hai già notato che JSX segue le regole XML nel senso che il componente Route può essere scritto come un tag: <Route />o due: <Route>...</Route>. Questo è vero per tutti i JSX inclusi i componenti personalizzati e i normali nodi DOM. Ad esempio, <div /> è JSX valido e convertirà in <div></div> quando viene eseguito il rendering.

Per brevità, immagina che WidgetListassomigli a UserList.

Poiché <Route component={SearchLayout}> ha ora due percorsi figlio, l’utente può visitare /users o /widgets e il corrispondente <Route> caricherà i rispettivi componenti all’interno del componente SearchLayout.

Inoltre, si noti come il componente Home verrà posizionato direttamente all’interno di MainLayout senza che SearchLayout venga coinvolto, a causa del modo in cui i <Route>sono annidati. Probabilmente puoi immaginare che sia facile riorganizzare il modo in cui i layout e i componenti sono annidati riorganizzando i percorsi.

IndexRoutes

React Router è molto espressivo e spesso c’è più di un modo per fare la stessa cosa. Ad esempio potremmo anche aver scritto il router sopra in questo modo:

ReactDOM.render(( <Router> <Route path="/" component={MainLayout}> <IndexRoute component={Home} /> <Route component={SearchLayout}> <Route path="users" component={UserList} /> <Route path="widgets" component={WidgetList} /> </Route> </Route> </Router>), document.getElementById('root'));

Nonostante il suo aspetto diverso, entrambi funzionano esattamente allo stesso modo.

Attributi di percorso opzionali

A volte, <Route> avrà un attributo component con no path, come nel percorso SearchLayout dall’alto. Altre volte, potrebbe essere necessario avere un <Route> con un path e no component. Per capire perché, iniziamo con questo esempio:

<Route path="product/settings" component={ProductSettings} /><Route path="product/inventory" component={ProductInventory} /><Route path="product/orders" component={ProductOrders} />

La porzione /product di path è ripetitiva. Possiamo rimuovere la ripetizione avvolgendo tutti e tre i percorsi in un nuovo <Route>:

<Route path="product"> <Route path="settings" component={ProductSettings} /> <Route path="inventory" component={ProductInventory} /> <Route path="orders" component={ProductOrders} /></Route>

Anche in questo caso, React Router mostra la sua espressività. Quiz: hai notato il problema con entrambe le soluzioni? Al momento non abbiamo regole per quando l’utente visita il percorso /product.

Per risolvere questo problema, possiamo aggiungere un IndexRoute:

<Route path="product"> <IndexRoute component={ProductProfile} /> <Route path="settings" component={ProductSettings} /> <Route path="inventory" component={ProductInventory} /> <Route path="orders" component={ProductOrders} /></Route>

Usa <Link> non <a>

Quando crei ancore per i tuoi percorsi, dovrai usare <Link to="">invece di <a href="">. Non preoccupatevi però, quando si utilizza il componente <Link>, React Router alla fine vi darà un ancoraggio ordinario nel DOM. L’utilizzo di <Link> è necessario per il Router React per eseguire alcune delle sue magie di routing.

Aggiungiamo alcuni link (ancore) al nostro MainLayout:

var MainLayout = React.createClass({ render: function() { return ( <div className="app"> <header className="primary-header"></header> <aside className="primary-aside"> <ul> <li><Link to="/">Home</Link></li> <li><Link to="/users">Users</Link></li> <li><Link to="/widgets">Widgets</Link></li> </ul> </aside> <main> {this.props.children} </main> </div> ); }});

Gli attributi sui componenti <Link> verranno passati all’ancora che creano. Quindi questo JSX:

<Link to="/users" className="users">

Diventerà questo in DOM:

<a href="/users" class="users">

Se è necessario creare un ancoraggio per percorsi non router, ad esempio un sito Web esterno, utilizzare i normali tag di ancoraggio come al solito. Per ulteriori informazioni, consultare la documentazione di IndexRoute e Link.

Collegamenti attivi

Una caratteristica interessante del componente <Link> è la sua capacità di sapere quando è attivo:

<Link to="/users" activeClassName="active">Users</Link>

Se l’utente si trova sul percorso /users, il router cercherà le ancore corrispondenti che sono state create con <Link> e alternerà la loro classe active. Vedi di più su questa funzione.

Cronologia del browser

Per evitare confusione, ho lasciato fuori un dettaglio importante fino ad ora. Il <Router> deve sapere quale strategia di monitoraggio della cronologia utilizzare. React Router docs consiglia Browserstory che è implementato come segue:

var browserHistory = ReactRouter.browserHistory;ReactDOM.render(( <Router history={browserHistory}> ... </Router>), document.getElementById('root'));

Nelle versioni precedenti di React Router, l’attributo history non era richiesto e l’impostazione predefinita era utilizzare hashHistory. Come suggerisce il nome, ha utilizzato un segno hash # nell’URL per gestire il routing in stile SPA front-end, simile a quello che ci si potrebbe aspettare da una spina dorsale.router js.

Con hashHistory, gli URL saranno simili a questo:

  • example.com
  • example.com/#/users?_k=ckuvup
  • example.com/#/widgets?_k=ckuvup

Che succede con quelle brutte stringhe di query?

Quando viene implementato browserHistory, i percorsi sembrano più organici:

  • example.com
  • example.com/users
  • esempio.com / widgets

C’è un avvertimento sul server quando browserHistory viene utilizzato sul front-end. Se l’utente inizia la visita a example.com e quindi passa a /users e /widgets, React Router gestisce questo scenario come previsto. Tuttavia, se l’utente inizia la sua visita digitando example.com/widgets direttamente nel browser, o se si aggiorna su example.com/widgets, allora il browser deve fare almeno una richiesta al server per /widgets. Se non c’è un router lato server, questo fornirà un 404:

Attenzione con gli URL. Avrete bisogno di un router lato server.

Per risolvere il problema 404 dal server, React Router consiglia un router con caratteri jolly sul lato server. Con questa strategia, non importa quale percorso lato server viene chiamato, il server dovrebbe sempre servire lo stesso file HTML. Quindi, se l’utente inizia direttamente da example.com/widgets, anche se viene restituito lo stesso file HTML, React Router è abbastanza intelligente da caricare il componente corretto.

L’utente non noterà nulla di strano, ma potresti avere dubbi sul servire sempre lo stesso file HTML. Negli esempi di codice, questa serie continuerà a utilizzare la strategia “wildcard router”, ma spetta a te gestire il routing lato server in modi che ritieni opportuni.

React Router può essere utilizzato sia sul lato server che sul lato client in modo isomorfo? Certo che può, ma questo è ben oltre lo scopo di questo tutorial.

Reindirizza con browserHistory

L’oggetto browserHistory è un singleton in modo da poterlo includere in qualsiasi file. Se è necessario reindirizzare manualmente l’utente in qualsiasi codice, è possibile utilizzare il metodo push per farlo:

browserHistory.push('/some/path');

Route Matching

React router gestisce la route matching in modo simile ad altri router:

<Route path="users/:userId" component={UserProfile} />

Questo percorso corrisponderà quando l’utente visita qualsiasi percorso che inizia con users/ e ha qualsiasi valore in seguito. Corrisponderà a /users/1, /users/143 o anche /users/abc (che dovrai convalidare da solo).

React Router passerà il valore per :userIdcome puntello a UserProfile. Questo props è accessibile come this.props.params.userId all’interno di UserProfile.

Router Demo

A questo punto, abbiamo abbastanza codice per mostrare una demo.

Vedere la Penna React-Router Demo di Brad Westfall (@bradwestfall) su CodePen.

Se hai fatto clic su alcuni percorsi nell’esempio, potresti notare che i pulsanti indietro e avanti del browser funzionano con il router. Questo è uno dei motivi principali per cui esistono queste strategie history. Inoltre, tieni presente che con ogni percorso che visiti, non vengono fatte richieste al server tranne la prima per ottenere l’HTML iniziale. Quanto e ‘ figo?

ES6

Nel nostro esempio CodePen, React, ReactDOM e ReactRouter sono variabili globali da una CDN. All’interno dell’oggetto ReactRouter ci sono tutti i tipi di cose di cui abbiamo bisogno come i componenti Router e Route. Quindi potremmo usare ReactRouter in questo modo:

ReactDOM.render(( <ReactRouter.Router> <ReactRouter.Route ... /> </ReactRouter.Router>), document.getElementById('root'));

Qui, dobbiamo prefisso tutti i nostri componenti del router con il loro oggetto genitore ReactRouter. Oppure potremmo usare la nuova sintassi destrutturante di ES6 come questa:

var { Router, Route, IndexRoute, Link } = ReactRouter

Questo “estrae” parti di ReactRouter in variabili normali in modo che possiamo accedervi direttamente.

A partire da ora, gli esempi di questa serie utilizzeranno una varietà di sintassi ES6 tra cui la destrutturazione, l’operatore di diffusione, le importazioni/esportazioni e forse altri. Ci sarà una breve spiegazione di ogni nuova sintassi man mano che appaiono e il repository GitHub fornito con questa serie ha anche molte spiegazioni ES6.

In bundle con webpack e Babel

Come affermato in precedenza, questa serie viene fornita con un repository GitHub in modo da poter sperimentare con il codice. Dal momento che assomiglierà alla stoffa di una SPA del mondo reale, utilizzerà strumenti come webpack e Babel.

  • webpack raggruppa più file JavaScript in un unico file per il browser.
  • Babel convertirà il codice ES6 (ES2015) in ES5, poiché la maggior parte dei browser non comprende ancora tutto ES6. Poiché questo articolo invecchia, i browser supporteranno ES6 e Babel potrebbe non essere necessario.

Se non sei ancora troppo a tuo agio nell’usare questi strumenti, non preoccuparti, il codice di esempio ha già tutto configurato in modo da poterti concentrare su React. Ma assicurati di rivedere il codice di esempio README.md file per documentazione aggiuntiva del flusso di lavoro.

Fai attenzione alla sintassi deprecata

La ricerca di informazioni su Google su React Router potrebbe farti atterrare su uno dei tanti articoli o pagine StackOverflow che sono stati scritti quando React Router era nella sua versione pre-1.0. Molte caratteristiche dal pre-1.0 release sono deprecati ora. Ecco una breve lista:

  • <Route name="" /> è deprecato. Usa invece <Route path="" />.
  • <Route handler="" /> è deprecato. Usa invece <Route component="" />.
  • <NotFoundRoute /> è deprecato. Vedere Alternativa
  • <RouteHandler /> è deprecato.
  • willTransitionTo è deprecato. Vedere onEnter
  • willTransitionFrom è deprecato. Vedere onLeave
  • “Posizioni” sono ora chiamati “storie”.

Vedi l’elenco completo per 1.0.0 e 2.0.0

Ci sono ancora più funzionalità in React Router che non sono state mostrate, quindi assicurati di controllare i documenti API. I creatori di React Router hanno anche creato un tutorial passo-passo per React Router e anche checkout questo reagire.video js Conf su come è stato creato React Router.

Un ringraziamento speciale a Lynn Fisher per l’opera d’arte @lynnandtonic

Serie di articoli:

  1. Reagire Router (Tu sei qui!)
  2. Componenti contenitore
  3. Redux

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.