Mød Material-UI - dit nye foretrukne brugergrænsefladebibliotek

Opdatering (17/05/2018): Material-UI v1.0.0 er ude! Tjek dette indlæg af Olivier.

Huh? Endnu et bibliotek? Hvad er der galt med Bootstrap? Og hvorfor ikke v0.20?

Store spørgsmål! Lad os starte med en kort introduktion. Kort sagt er Material-UI et open source-projekt, der indeholder React-komponenter, der implementerer Googles materialdesign.

Det startede i 2014, ikke længe efter at React kom ud til offentligheden, og er vokset i popularitet lige siden. Med over 35.000 stjerner på GitHub er Material-UI et af de bedste brugergrænsefladebiblioteker til React derude.

Dets succes kom dog ikke uden udfordringer. Designet med mindre, var Material-UI v0.x tilbøjelig til almindelige CSS-faldgruber, såsom globalt omfang, der fører projektet på CSS-in-JS-banen. Sådan kom det næste gang i 2016.

Rejsen mod bedre stil, som Olivier Tassinari udtrykker det, begyndte med inline-stilarter, men deres suboptimale ydeevne og begrænsede funktionsstøtte (tænk pseudo-vælgere eller medieforespørgsler) gjorde i sidste ende teamets overgang til JSS. Og dreng tog de et smart valg.

Hvad er hype med v1-udgivelsen?

Det er ondt. Ikke kun adresserer de problemer, der er forbundet med MINDRE, men det låser også et væld af fantastiske funktioner inkl

  • dynamiske stilarter genereret ved kørsel
  • indlejrede temaer med intuitiv tilsidesættelse
  • reduceret belastningstid med kodespaltning

Og mange flere. Biblioteket er også modent nok til at blive brugt i produktionen Så meget, at teamet foreslår v1 til alle nye projekter fremover.

Okay, skal vi bygge en app, eller hvad?

Glad for du spurgte! Til denne demo bygger vi en simpel fitness-app. Alle keder sig nu af to-do-apps nu, ikke?

Læsning er fantastisk og alt, men at se er ofte sjovere! Tjek denne playliste, jeg lavede på YouTube, hvis du vil opbygge en mere avanceret app.

Ok, du fik mig overbevist. Hvordan kommer jeg i gang?

Vi starter første gang på vores app med create-react-app

oprette-reagere-app-mui-fitness
cd mui-fitness
kode.

Og hvad med Material-UI?

Hvis du har garn, er installationen så enkel som

garn tilføj @ material-ui / core

Ellers med npm

npm i @ material-ui / core

For ikke længe siden specificerede vi @ næste tag for at hente den seneste pre-release (f.eks. Kunne det have set ud som v1.0.0-beta.47). Nu hvor både v1 og v0.x er under materiale-ui-omfang, er vi nødt til at referere til bibliotekets kerne med / core for at målrette mod den nyeste udgivelse. Gå ikke glip af den sidste del, ellers vil du ende med den stabile0.20-afhængighed!

Vent, er det virkelig det?

Næsten! En sidste ting er skrifttyper. Vi følger den anbefalede Roboto-skrifttype fra Googles CDN:

Alternativt kan du trække det ind fra NPM med

garn tilføj skrifttype-roboto
# eller npm i typeface-roboto

i hvilket tilfælde skal du have en import ved roden til dit projekt

// Sørg for, at du dog kun indlæser skriftvægter på 300, 400 og 500!
import 'typeface-roboto'

Færdig! Hvad gør jeg derefter?

Lad os refaktorere vores App.js-komponent, før vi går videre

import React, {Component} fra 'react'
eksport standardklasse App udvider komponent {
  tilstand = {
    øvelser: [],
    titel: ''
  }
  render () {
    return 

Øvelser

  } }

Og hvorfor ikke rydde op i index.js, mens vi er ved det?

import React fra 'react'
import {render} fra 'react-dom'
importer app fra './App'
render (, document.getElementById ('root'))

Fjern de resterende filer under src, da vi ikke har brug for dem.

Hvor kommer Material-UI ind?

Fair nok, det er tid til at se det i aktion. Lad os ændre den grimme h1 til en smuk overskrift af Typografi:

importer typografi fra '@ material-ui / core / typography'
...
  render () {
    Vend tilbage (
      
        Øvelser
      
    )
  }
}
Bemærk, at siden v1.0.0-rc.0 flyttede MUI til @ material-ui / core, og importstien blev udfladet. Dette var den sidste banebrydende ændring i pre-release.

Gå derefter videre og løb garn og se magien.

Vi er i gang med en god start! Typografikomponent leveres med et foruddefineret sæt af typestørrelser. Andre varianter inkluderer body1, title, display2 osv. Blandt andre indbyggede rekvisitter er justering, som vi bruger her til at centrere teksten vandret, og gutterBottom, der tilføjer en bundmargen.

Hvorfor udvider vi ikke dette til en form, så vi kan oprette vores egne øvelser? Vi starter med et TextField og binder det til titlen på staten

importer typografi fra '@ material-ui / core / typography'
importer TextField fra '@ material-ui / core / TextField'
...
  handleChange = ({target: {name, value}}) =>
    this.setState ({
      [navn]: værdi
    })
  render () {
    const {title} = this.state
    Vend tilbage (
      ...
      
                    )   } }

Selvfølgelig er vi nødt til at gøre React glad ved at indpakke typografi og form med et overordnet element. Hvad kan være en bedre mulighed for en papir-lignende kortlignende baggrund? Lad os nå ud til papiret

importer papir fra '@ material-ui / core / Paper'
...
  render () {
      const {title} = this.state
      returner 
        ...
      
    }
  }
}

Det er også på tide at begynde at bruge navngivne importer (hvis vi antager, at vores Webpack-opsætning tillader træ rysten):

import {Papir, Typografi, TextField} fra '@ material-ui / core'

Sød! Og hvad er en formular uden at indsende knappen? Knapper er en hæftekomponent i materiale-UI; du kan se dem overalt. For eksempel,

import {
  Papir,
  Typografi,
  Tekstfelt,
  Knap
} fra '@ material-ui / core'

...

        
          skab
        
      
    
  }
}

Det skal læse godt. type er en almindelig React-prop, farve og variant er Materiale-UI-specifik og udgør en rektangelformet knap. En anden variant er fx en flydende knap.

Ikke verdens smukkeste form, men vi får den til at se bedre ud i et øjeblik!

Det gør dog ikke meget. Vi bliver nødt til at aflytte begivenheden til formularindgivelse

    returner 
      ...
      
        ...
      
    
  }
}

og håndter det derefter med

  handleCreate = e => {
    e.preventDefault ()
    if (this.state.title) {
      this.setState (({{øvelser, titel}) => ({
        øvelser: [
          ...øvelser,
          {
            titel,
            id: Date.now ()
          }
        ],
        titel: ''
      }))
    }
  }

Whoa! Hvad handler den kryptiske kode om? Meget hurtigt, vi

  1. Undgå genindlæsning af standardsiden
  2. Kontroller, om titelfeltet ikke er tomt
  3. Indstil staten med en opdateringsfunktion til at afbøde async-opdateringer
  4. Ødelæg øvelser og titel det prevState-objekt
  5. Spred øvelserne på den næste tilstand med et nyt øvelsesobjekt
  6. Nulstil titlen for at rydde inputfeltet

Gæt, at jeg også burde have nævnt, at jeg er forelsket i ES6. Er vi ikke alle?

Men hvordan lister vi dem op?

Nu er det rigtige tidspunkt at gøre. Er der en listekomponent? Naturligvis, din fjollede gås!

På en liste går vi gennem vores øvelser og returnerer et ListItem med nogle ListItemText for hver

import {List, ListItem, ListItemText} fra '@ material-ui / core'
...
  render () {
    const {title, øvelser} = this.state
    returner 
      ...
      
        {øvelser.map (({id, titel}) =>
          
            
          
        )}
      
    
  }
}

Lad os også kode nogle få indledende øvelser for at få noget på skærmen. Du gætte på det, treenigheden i alle vægtløftningstræner, damer og herrer:

  tilstand = {
    øvelser: [
      {id: 1, titel: 'Bench Press'},
      {id: 2, titel: 'Deadlift'},
      {id: 3, titel: 'Squats'}
    ],
    titel: ''
  }
Vi kan nu oprette og liste vores øvelser!

Sidst, men ikke mindst, laver vores brugere sandsynligvis skrivefejl, så vi bedes tilføje en sletningsknapp ved siden af ​​hver øvelse, så de kunne fjerne poster, de ikke længere ønsker på deres liste.

Vi kan bruge ListItemSecondaryAction til at gøre nøjagtigt det. Placeret helt til højre for listeposten kan det indeholde et sekundært kontrolelement, f.eks. En IconButton med en vis handling

import {
  /*...*/,
  ListItemSecondaryAction,
  IconButton
} fra '@ material-ui / core'
...
          
            
            
               this.handleDelete (id)}
              >
                {/ * ??? * /}
              
            
          
...

Og lad os ikke glemme slettehåndtereren så godt:

  handleDelete = id =>
    this.setState (({{øvelser}) => ({
      øvelser: øvelser.filter (ex => ex.id! == id)
    }))

som simpelthen filtrerer vores øvelser ned til dem, der ikke matcher id'et for den, der skal fjernes.

Kan vi have et papirkurvsikon inde i knappen?

Ja, det ville være dejligt! Selvom du kunne bruge Materielle ikoner fra Googles CDN direkte med enten Ikon- eller SvgIcon-komponenter, foretrækkes det ofte at gå med en færdiglavet forudindstilling.

Heldigvis er der en Material-UI-pakke til dem

garn tilføj @ material-ui / ikoner
# eller npm i @ material-ui / ikoner

Det eksporterer 900+ officielle materialeikoner som React-komponenter, og ikonnavne er næsten identiske, som du vil se nedenfor.

Lad os sige, at vi ville tilføje et papirkurvsikon. Vi går først over til material.io/icons for at finde ud af dets nøjagtige navn

Google tilbyder to varianter af papirkurvikonet,

Derefter forvandler vi dette navn til PascalCase i vores importsti

import Slet fra '@ material-ui / ikoner / Slet'

Ligesom med materialer-UI-komponenter, hvis din opsætning er aktiveret af trækrystning, kan du forkorte importen til

import {Slet} fra '@ material-ui / ikoner'

hvilket er især nyttigt, når du importerer flere ikoner på én gang.

Nu hvor vi har vores papirkurvsikon, lad os vise det inde i vores slet-knap

 this.handleDelete (id)}>
  
Og med det kan vores CRUD-app MVP betragtes som udført!

Hvordan kan jeg få formen til at se mindre grim ud?

Ah, styling. Jeg troede, du aldrig ville spørge! Et blidt strejf af CSS ville ikke skade. Så importerer vi et eksternt stilark med globale stilarter? Eller måske bruge CSS-moduler og tildele scoped-klassens navne til vores elementer? Ikke helt.

Under hætten gaffer Material-UI et CSS-in-JS-bibliotek kendt som react-jss.

Det er en React-integration af JSS-biblioteket af den samme forfatter, Oleg Isonen. Kan du huske, at vi rørte ved det i starten? Dets grundide er at gøre det muligt for dig at definere stilarter i JavaScript. Hvad der dog får JSS til at skille sig ud blandt andre libs, er dens support til SSR, lille bundtestørrelse og rig plugin support.

Lad os prøve det! Opret et stilartsobjekt i vores App-komponent, som du ville gøre med inline-stilarter. Kom derefter på en nøgle, for eksempel rod, der henviser til rodpapirelementet, og skriv nogle stilarter i camelCase

const stilarter = {
  rod: {
    margen: 20,
    polstring: 20,
    maxBredde: 400
  }
}

Importer derefter withStyles HOC fra material-ui

import {withStyles} fra '@ material-ui / core / styles'

og indpak App-komponenten med den, idet den passerer typografiobjekt som arg

eksporter standard medStyles (stilarter) (
  klasse App udvider komponent {
    ...
  }
)
Bemærk, at du også kan bruge withStyles HOC som dekoratør. Husk, at oprettelse-reaktion-reaktion ikke understøtter dekoratører ude af kassen endnu, så hvis du insisterer på at bruge dem, skal du skubbe ud eller gafle for at finpusse konfigurationen.

Dette vil injicere en klasser prop i app indeholdende et dynamisk genereret klassens navn til vores rodelement

console.log (this.props) afslører et klasseobjekt

Klassenavnet er garanteret unikt, og det bliver ofte forkortet i en produktionsbygning. Vi tildeler det derefter til Paper via className-attribut

    render () {
      const {title, øvelser} = this.state
      const {classes} = this.props
      return 
        ...
      
    }
Papirkomponent med grundlæggende styling anvendt

Hvordan fungerer denne magi? Det viser sig, withStyles er ansvarlig for det beskidte arbejde. Bag kulisserne sprøjtede det en række stilarter ind i DOM under