React ha fatto molto per semplificare lo sviluppo del web. L'architettura basata su componenti di React semplifica in linea di principio la scomposizione e il riutilizzo del codice. Tuttavia, non è sempre chiaro agli sviluppatori come condividere i loro componenti tra i progetti. In questo post, ti mostrerò alcuni modi per risolverlo.
React ha reso più facile scrivere codice bello ed espressivo. Tuttavia, senza schemi chiari per il riutilizzo dei componenti, il codice diventa divergente nel tempo e diventa molto difficile da mantenere. Ho visto codebase in cui lo stesso elemento dell'interfaccia utente aveva dieci diverse implementazioni! Un altro problema è che, il più delle volte, gli sviluppatori tendono ad accoppiare l'interfaccia utente e la funzionalità aziendale troppo strettamente e lottano più tardi quando l'interfaccia utente cambia.
Oggi vedremo come possiamo creare componenti dell'interfaccia utente condivisibili e come stabilire un linguaggio di progettazione coerente nell'intera applicazione.
Hai bisogno di un progetto di React vuoto per iniziare. Il modo più rapido per farlo è attraverso l'app crea-react, ma con questo si impegna a configurare Sass. Ho creato un'app skeleton, che puoi clonare da GitHub. Puoi anche trovare il progetto finale nel nostro tutorial GitHub repo.
Per correre, fai a filati-installazione
per estrarre tutte le dipendenze e quindi eseguire inizio del filo
per far apparire l'applicazione.
Tutti i componenti visivi risiedono sotto il design_system cartella con gli stili corrispondenti. Tutti gli stili o le variabili globali saranno sotto src / stili.
Quand'è stata l'ultima volta che hai avuto un look da te sconosciuto ai tuoi colleghi di design, per aver sbagliato il padding di mezzo pixel o non essere in grado di distinguere tra varie sfumature di grigio? (C'è una differenza tra #eee
e #efefef
, Mi è stato detto, e ho intenzione di scoprirlo uno di questi giorni.)
Uno degli obiettivi della creazione di una libreria dell'interfaccia utente è migliorare la relazione tra il team di progettazione e di sviluppo. Gli sviluppatori front-end collaborano da tempo con i progettisti dell'API e sono in grado di stabilire contratti API. Ma per qualche ragione, ci sfugge mentre si coordina con il team di progettazione. Se ci pensi, ci sono solo un numero finito di stati in cui un elemento UI può esistere. Se dobbiamo progettare un componente Heading, per esempio, può essere qualsiasi cosa tra h1
e h6
e può essere in grassetto, in corsivo o sottolineato. Dovrebbe essere semplice codificarlo.
Il primo passo prima di intraprendere qualsiasi progetto di design è capire come sono strutturate le griglie. Per molte app, è solo casuale. Ciò porta a un sistema di spaziatura sparsa e rende molto difficile per gli sviluppatori valutare quale sistema di spaziatura utilizzare. Quindi scegli un sistema! Mi sono innamorato del sistema a griglia 4px - 8px quando l'ho letto per la prima volta. Attenersi a ciò ha contribuito a semplificare un sacco di problemi di stile.
Iniziamo impostando un sistema di griglia di base nel codice. Inizieremo con un componente dell'app che definisce il layout.
//src/App.js importa React, Component da 'react'; importare il logo da './logo.svg'; importare './App.scss'; importa Flex, Page, Box, BoxStyle da './design_system/layouts / Loutouts'; la classe App estende Component render () return (); Esporta l'app predefinita;Costruisci un sistema di design con React
Un semplice flexbox mezzo e questo va a destra
Successivamente, definiamo un numero di stili e componenti wrapper.
//design-system/layouts/Layout.js import Reagire da 'react'; importare './layout.scss'; export const BoxBorderStyle = default: 'ds-box-border - default', light: 'ds-box-border - light', spesso: 'ds-box-border - thick', export const BoxStyle = default: 'ds-box - default', doubleSpace: 'ds-box - double-space', noSpace: 'ds-box - no-space' export const Pagina = (children, fullWidth = true) => const classNames = 'ds-page $ fullWidth? 'ds-page - fullwidth': " '; return (bambini); ; export const Flex = (children, lastElRight) => const classNames = 'flex $ lastElRight? 'flex-align-right': " '; return (bambini); ; export const Box = (children, borderStyle = BoxBorderStyle.default, boxStyle = BoxStyle.default, fullWidth = true) => const classNames = 'ds-box $ borderStyle $ boxStyle $ fullWidth? 'ds-box - fullwidth': " '; return (bambini); ;
Infine, definiremo i nostri stili CSS in SCSS.
/*design-system/layouts/layout.scss * / @import '... / ... /styles/variables.scss'; $ base-padding: $ base-px * 2; .flex display: flex; & .flex-align-right> div: last-child margin-left: auto; .ds-page border: 0px solid # 333; border-left-width: 1px; border-right-width: 1px; &: not (.ds-page - fullwidth) margin: 0 auto; larghezza massima: 960 px; & .ds-page - fullwidth larghezza massima: 100%; margine: 0 $ base-px * 10; .ds-box border-color: # f9f9f9; border-style: solido; allineamento del testo: a sinistra; & .ds-box - fullwidth width: 100%; & .ds-box-border - light border: 1px; & .ds-box-border - thick border-width: $ base-px; & .ds-box - default padding: $ base-padding; & .ds-box - double-space padding: $ base-padding * 2; & .ds-box - default - no-space padding: 0;
C'è molto da disfare qui. Iniziamo dal basso. variables.scss è dove definiamo i nostri globals come il colore e impostiamo la griglia. Dal momento che stiamo usando la griglia 4px-8px, la nostra base sarà 4px. Il componente principale è Pagina
, e questo controlla il flusso della pagina. Quindi l'elemento di livello più basso è a Scatola
, che determina come viene eseguito il rendering dei contenuti in una pagina. È solo un div
che sa come renderizzarsi contestualmente.
Ora, abbiamo bisogno di un Contenitore
componente che si incolla più volte div
S. Abbiamo scelto flex-box
, da qui il nome creativo Flettere
componente.
Il sistema di tipi è un componente critico di qualsiasi applicazione. Di solito, definiamo una base attraverso gli stili globali e sovrascriviamo come e quando necessario. Questo spesso porta a incongruenze nel design. Vediamo come questo può essere facilmente risolto aggiungendo alla libreria di progettazione.
Innanzitutto, definiremo alcune costanti di stile e una classe wrapper.
// design-system / type / Type.js import React, Component da 'react'; importare './type.scss'; export const TextSize = default: 'ds-text-size - default', sm: 'ds-text-size - sm', lg: 'ds-text-size - lg'; export const TextBold = default: 'ds-text - default', semibold: 'ds-text - semibold', grassetto: 'ds-text - bold'; export const Type = (tag = 'span', size = TextSize.default, boldness = TextBold.default, children) => const Tag = '$ tag'; const classNames = 'ds-text $ size $ boldness'; ritornobambini ;
Successivamente, definiremo gli stili CSS che verranno utilizzati per gli elementi di testo.
/ * design-system / type / type.scss * / @import '... / ... /styles/variables.scss'; $ base-font: $ base-px * 4; .ds-text line-height: 1.8em; & .ds-text-size - default font-size: $ base-font; & .ds-text-size - sm dimensione font: $ base-font - $ base-px; & .ds-text-size - lg font-size: $ base-font + $ base-px; & forte, & .ds-text - semibold font-weight: 600; & .ds-text - bold font-weight: 700;
Questo è semplice Testo
componente che rappresenta i vari stati dell'interfaccia utente. Può essere esteso ulteriormente per gestire microinterazioni come il rendering dei tooltip quando il testo viene ritagliato, o il rendering di un nugget diverso per casi speciali come email, tempo, ecc..
Finora, abbiamo creato solo gli elementi più elementari che possono esistere in un'applicazione web e non servono da soli. Espandiamoci su questo esempio costruendo una semplice finestra modale.
Per prima cosa, definiamo la classe del componente per la finestra modale.
// design-system / Portal.js import React, Component da 'react'; importare ReactDOM da 'react-dom'; importa Box, Flex da './layouts / Loutouts'; importare Type, TextSize, TextAlign da './type/Type'; importare './portal.scss'; export class Portal estende React.Component costruttore (oggetti di scena) super (oggetti di scena); this.el = document.createElement ('div'); componentDidMount () this.props.root.appendChild (this.el); componentWillUnmount () this.props.root.removeChild (this.el); render () return ReactDOM.createPortal (this.props.children, this.el,); export const Modal = (children, root, closeModal, header) => returnintestazione X bambini
Successivamente, possiamo definire gli stili CSS per il modale.
# modal-root .modal-wrapper background-color: white; border-radius: 10px; altezza massima: calc (100% - 100 px); larghezza massima: 560 px; larghezza: 100%; superiore: 35%; a sinistra: 35%; a destra: auto; fondo: auto; z-index: 990; posizione: assoluta; > div background-color: transparentize (nero, .5); posizione: assoluta; z-index: 980; inizio: 0; a destra: 0; a sinistra: 0; fondo: 0; .close cursor: pointer;
Per chi non lo sapesse, CreatePortal
è molto simile al rendere
metodo, tranne per il fatto che esegue il rendering dei child in un nodo esistente al di fuori della gerarchia DOM del componente principale. È stato introdotto in React 16.
Ora che il componente è definito, vediamo come possiamo utilizzarlo in un contesto aziendale.
//src/App.js importa React, Component da 'react'; // ... importa Type, TextBold, TextSize da './design_system/type/Type'; importare Modal da './design_system/Portal'; la classe App estende Component constructor () super (); this.state = showModal: false toggleModal () this.setState (showModal:! this.state.showModal); render () // ... this.state.showModal &&Test di rendering // ...
Possiamo usare il modale ovunque e mantenere lo stato nel chiamante. Semplice, vero? Ma c'è un bug qui. Il pulsante di chiusura non funziona. Questo perché abbiamo costruito tutti i componenti come un sistema chiuso. Semplicemente consuma gli oggetti di cui ha bisogno e trascura il resto. In questo contesto, la componente di testo ignora il al clic
gestore di eventi. Fortunatamente, questa è una soluzione semplice.
// In design-system / type / Type.js export const Tipo = (tag = 'span', dimensione = TextSize.default, boldness = TextBold.default, children, className = ", align = TextAlign.default, ... resto ) => const Tag = '$ tag'; const classNames = 'ds-text $ size $ boldness $ align $ className';bambini ;
ES6 ha un modo pratico per estrarre i restanti parametri come una matrice. Basta applicarlo e diffonderlo sul componente.
Mentre il tuo team scala, è difficile mettere tutti in sincronia sui componenti disponibili. Gli Storybook sono un ottimo modo per scoprire i tuoi componenti. Imposta un componente di base del libro di fiabe.
Per iniziare, esegui:
npm i -g @ storybook / cli bookstorybook
Questo imposta la configurazione richiesta per il libro di fiabe. Da qui, è un gioco da ragazzi fare il resto del setup. Aggiungiamo una semplice storia per rappresentare diversi stati di genere
.
import Reagire da "reagire"; import storiesOf da '@ storybook / react'; import Type, TextSize, TextBold da '... /design_system/type/Type.js'; storiesOf ('Type', module) .add ('default text', () => (Lorem ipsum )). add ('bold text', () => (Lorem ipsum )). add ('header text', () => (Lorem ipsum ));
La superficie dell'API è semplice. storiesOf
definisce una nuova storia, tipicamente il tuo componente. È quindi possibile creare un nuovo capitolo con Inserisci
, per mostrare i diversi stati di questo componente.
Naturalmente, questo è piuttosto semplice, ma i libri di fiabe hanno diversi componenti aggiuntivi che ti aiuteranno ad aggiungere funzionalità ai tuoi documenti. E ho detto che hanno supporto per le emoji? 😲
Progettare un sistema di progettazione da zero richiede molto lavoro e potrebbe non avere senso per un'app più piccola. Ma se il tuo prodotto è ricco e hai bisogno di molta flessibilità e controllo su ciò che stai creando, la tua libreria UI ti aiuterà nel lungo periodo.
Devo ancora vedere una buona libreria di componenti dell'interfaccia utente per React. La mia esperienza con react-bootstrap e material-ui (la libreria per React, cioè, non la struttura stessa) non era eccezionale. Invece di riutilizzare un'intera libreria dell'interfaccia utente, scegliere i singoli componenti potrebbe avere senso. Ad esempio, implementare la multi-selezione è un problema complesso di interfaccia utente e ci sono tonnellate di scenari da considerare. In questo caso, potrebbe essere più semplice utilizzare una libreria come React Select o Select2.
Una parola di cautela, però. Qualsiasi dipendenza esterna, in particolare i plugin dell'interfaccia utente, sono un rischio. Sono costretti a cambiare spesso le proprie API o, all'opposto, a continuare a utilizzare funzionalità obsolete e obsolete di React. Ciò potrebbe influire sulla consegna della tua tecnologia e qualsiasi modifica potrebbe essere costosa. Consiglierei di usare un wrapper su queste librerie, quindi sarà facile sostituire la libreria senza toccare più parti dell'app.
In questo post, ti ho mostrato alcuni modi per dividere la tua app in elementi visivi atomici, usandoli come blocchi Lego per ottenere l'effetto desiderato. Ciò facilita il riutilizzo del codice e la manutenibilità, oltre a semplificare il mantenimento di un'interfaccia utente coerente in tutta l'app.
Condividi le tue opinioni su questo articolo nella sezione dei commenti!