Att sätta Saker i Sammanhang Med att Reagera

0
37

Ramen är för närvarande en experimentell API för att Reagera⸺men snart för att vara en första klassens medborgare! Det finns en hel del anledningar till att det är intressant men det kanske mest är att det möjliggör för moderbolagets komponenter för att skicka data underförstått till sina barn, oavsett hur djupt den komponent trädet är. Med andra ord, data kan läggas till en förälder komponent och sedan alla barn som kan utnyttja det.

Se Pennan Reagera Sammanhang Lampor av Neal Fennimore (@nealfennimore) på CodePen.

Även om detta är ofta att använda fallet för att använda något som Redux, det är trevligt att använda om du inte behöver komplexa data management. Tycker om det! Vi skapar en anpassad nedströms av uppgifter, beslut som rekvisita är passerat och på vilken nivå. Ganska coolt.

Ramen är stor i områden där du har en hel del komponenter som är beroende av en enda bit av data, men är djupt inom den del träd. Uttryckligen passerar varje prop till varje enskild komponent kan ofta vara överväldigande och det är mycket lättare att bara använda sammanhang här.

Till exempel, låt oss fundera på hur vi normalt skulle passera rekvisita ner trädet. I det här fallet, vi passerar den röda färgen med hjälp av rekvisita på varje komponent för att flytta den på nedåt strömmen.

klass Förälder sträcker sig Reagera.Komponent {
render(){
återgå <Barnet color=”red”https://cdn.css-tricks.com/>;
}
}

klass Barn sträcker sig Reagera.Komponent {
render(){
återgå <Barnbarn färg={detta.rekvisita.color} />
}
}

klass Barnbarn sträcker sig Reagera.Komponent {
render(){
avkastning (
<div style={{color: med detta.rekvisita.färg}}>
Japp, jag är Barnbarn
</div>
);
}
}

Vad händer om vi aldrig ville ha Barn komponent för att ha prop i första hand? Sammanhang sparar oss med att gå igenom de Barn komponent med färg och skicka det direkt från Moderbolaget till Barnbarn:

klass Förälder sträcker sig Reagera.Komponent {
// Gör det möjligt för barn att använda sammanhang
getChildContext(){
return {
färg: “röd”
};
}

render(){
återgå <Barnet />;
}
}

Förälder.childContextTypes = {
färg: PropTypes.sträng
};

klass Barn sträcker sig Reagera.Komponent {
render(){
// Rekvisita tas bort och sammanhang flyter genom att Barnbarn
återgå <Barnbarn />
}
}

klass Barnbarn sträcker sig Reagera.Komponent {
render(){
avkastning (
<div style={{color: med detta.sammanhanget.färg}}>
Japp, jag är fortfarande Barnbarn
</div>
);
}
}

// Utsätta färg till Barnbarn
Barnbarn.contextTypes = {
färg: PropTypes.sträng
};

Och samtidigt något mer detaljerad, uppsidan är att exponera den färg som helst ner i den del träd. Jo, ibland…

Det är Några Gotchas

Du kan inte alltid ha din kaka och äta den också, och sammanhang i sin nuvarande form är inget undantag. Det finns några bakomliggande problem som du kommer mer än sannolikt att komma i kontakt med om du slutar att använda sammanhanget för alla utom de enklaste fallen.

Ramen är bra för att användas på en inledande göra. Uppdatering sammanhang på fluga? Inte så mycket. Ett vanligt problem med ramen är att ramen förändringar är inte alltid återspeglas i en komponent.

Låt oss dissekera dessa gotchas i mer detalj.

Gotcha 1: Att Använda Ren Komponenter

Ramen är svårt när du använder PureComponent sedan som standard inte utför någon grunt diffing som standard med sammanhang. Grunda diffing med PureComponent testar om värden av objektet är absolut lika. Om de inte gör det, då (och endast då) ska komponenten uppdatering. Men eftersom ramen inte är markerat, tja… ingenting händer.

Se Pennan Reagera Sammanhang Lyser med PureComponents av Neal Fennimore (@nealfennimore) på CodePen.

Gotcha 2: Bör Komponent Uppdatering? Kanske.

Sammanhang också inte uppdatera om en komponent är shouldComponentUpdate returnerar falskt. Om du har en egen shouldComponentUpdate metod, då kommer du också att behöva ta kontext i beaktande. För att aktivera uppdateringar med sammanhang, vi kan uppdatera varje enskild komponent med en anpassad shouldComponentUpdate som ser ut något liknande detta.

importera shallowEqual från “fbjs/lib/shallowEqual’;

klass ComponentThatNeedsColorContext sträcker sig Reagera.PureComponent {
// nextContext kommer att visa färg så snart som vi tillämpar ComponentThatNeedsColorContext.contextTypes
// OBS: Gör nedan kommer att visa en konsol fel kommer reagera v16.1.1
shouldComponentUpdate(nextProps, nextState, nextContext){
tillbaka !shallowEqual(det här.rekvisita, nextProps) || !shallowEqual(det här.staten, nextState) || !shallowEqual(det här.sammanhang, nextContext);
}
}

ComponentThatNeedsColorContext.contextTypes = {
färg: PropTypes.sträng
};

Detta innebär dock inte att lösa frågan om en mellanhand PureComponent mellan förälder och barn blockering sammanhang uppdateringar. Detta innebär att varje PureComponent mellan förälder och barn skulle behöva ha contextTypes definieras på det, och de skulle också behöva ha en uppdaterad shouldComponentUpdate metod. Och på denna punkt, det är mycket jobb för väldigt lite vinst.

Bättre Metoder för Gotchas

Lyckligtvis har vi några olika sätt att arbeta runt gotchas.

Metod 1: Använd en Högre Ordning Komponent

En Högre Ordning Komponent kan läsa från sammanhang och passera den nödvändiga värden på till nästa komponent som en prop.

importera Reagerar från ‘reagerar’;

const withColor = (WrappedComponent) => {
klass ColorHOC sträcker sig Reagera.Komponent {
render(){
const { color } = i detta.sammanhanget.
återgå <WrappedComponent style={{color: color}} {…här.rekvisita} />
}
}

ColorHOC.contextTypes = {
färg: Reagera.PropTypes.sträng
};

tillbaka ColorHOC;
};

export const-Knappen = (rekvisita)=> knappen <{…rekvisita}>Knappen</button>

// ColoredButton kommer att göra med vilken färg är för närvarande i samband med en stil prop
export const ColoredButton = withColor( Knappen );

Se Pennan Reagera Sammanhang Lyser med HOC av Neal Fennimore (@nealfennimore) på CodePen.

Metod 2: Använd Göra Rekvisita

Göra Rekvisita tillåter oss att använda rekvisita för att dela kod mellan två komponenter.

klass App sträcker sig Reagera.Komponent {
getChildContext(){
return {
färg: “röd”
}
}

render() {
avkastning på Knappen < / >
}
}

App.childContextTypes = {
färg: Reagera.PropTypes.sträng
}

// Krok “Färg” i ‘App’ sammanhanget
klass Färg sträcker sig Reagera.Komponent {
render() {
tillbaka detta.rekvisita.render(det här.sammanhanget.färg);
}
}

Färg.contextTypes = {
färg: Reagera.PropTypes.sträng
}

klass Knappen sträcker sig Reagera.Komponent {
render(){
avkastning (
<button type=”button”>
{/* Avkastning färgade texten i Knappen */}
<Färgen återges={ color => (
<Textfärg={color} text=”Text” />
) } />
</button>
)
}
}

Sms: a klass sträcker sig Reagera.Komponent {
render(){
avkastning (

{detta.rekvisita.text och tryck på}

)
}
}

Sms: a.propTypes = {
text: Reagera.PropTypes.sträng,
färg: Reagera.PropTypes.sträng,
}</Color></button>
Strategi 3: Dependency Injection

Ett tredje sätt vi kan arbeta kring dessa gotchas är att använda Dependency Injection för att begränsa sammanhang API och låta komponenter för att prenumerera som behövs.

Den Nya Sammanhang

Det nya sättet att använda sammanhang, som just nu planeras för nästa mindre utsläpp av Reagera (16.3), har fördelar av att vara mer lättläst och lättare att skriva utan “gotchas” från tidigare versioner. Vi har nu en ny metod som kallas createContext, som definierar ett nytt sammanhang och returnerar både Leverantör och Konsument.

Leverantören skapar ett sammanhang att alla sub-komponenter kan haka på. Det är hooked på via Konsumenter som använder en render prop. Det första argumentet för att göra prop funktion, är det värde som vi har gett till Leverantören. Genom att uppdatera värdet inom Leverantör, alla konsumenter kommer att uppdateras för att återspegla den nya värde.

Som en bieffekt med hjälp av den nya sammanhang, att vi inte längre har att använda childContextTypes, getChildContext, och contextTypes.

const ColorContext = Reagera.createContext (“color”);
klass ColorProvider sträcker sig Reagera.Komponent {
render(){
avkastning (
<ColorContext.Leverantör värde={‘red’}>
{ detta.rekvisita.barnen }
</ColorContext.Leverantören>
)
}
}

klass Förälder sträcker sig Reagera.Komponent {
render(){
// Linda ‘Barn’ med vår leverantör färg
avkastning (
<ColorProvider>
<Barnet />
</ColorProvider>
);
}
}

klass Barn sträcker sig Reagera.Komponent {
render(){
återgå <Barnbarn />
}
}

klass Barnbarn sträcker sig Reagera.Komponent {
render(){
// Förbruka våra sammanhang och passera färg till style-attributet
avkastning (
<ColorContext.Konsumenten>
{/* ‘färg’ är det värde från vår Leverantör */}
{
färg => (
<div style={{color: color}}>
Japp, jag är fortfarande Barnbarn
</div>
)
}
</ColorContext.Konsumenten>
);
}
}

Separat Sammanhang

Eftersom vi har bättre kontroll på hur vi utsätter sammanhang och vilka komponenter som är tillåtna att använda det, kan vi individuellt wrap komponenter med olika sammanhang, även om de bor i samma komponent. Vi kan se detta i nästa exempel, där med hjälp av LightProvider två gånger, vi kan ge två komponenter separat sammanhang.

Se Pennan Reagera Sammanhang Lyser med nytt Sammanhang, av Neal Fennimore (@nealfennimore) på CodePen.

Slutsats

Ramen är ett kraftfullt API, men det är också mycket lätt att använda på ett felaktigt sätt. Det finns också några varningar för att använda det, och det kan vara mycket svårt att räkna ut frågor när komponenter gå snett. Medan Högre För Komponenter och dependency injection erbjuda alternativ för de flesta fall, sammanhang kan användas fördelaktigt i isolerade delar av din kodbas.

Med nästa sammanhang även om vi inte längre oroa dig för att den gotchas vi hade med den tidigare versionen. Det tar bort med att definiera contextTypes på enskilda komponenter och öppnar upp möjligheter för att definiera nya sammanhang i en återanvändbar sätt.