React: Gibt es eine Möglichkeit, in ComponentDidMount auf eine neue Kontext-API zuzugreifen?

Erstellt am 18. März 2018  ·  41Kommentare  ·  Quelle: facebook/react

Wir bauen ein React Mapbox Gl-Modul und verwenden heute Klon- und Injektionsrequisiten.

Wir haben versucht, die 16.2.0-Kontext-API zu verwenden, aber ich habe gesehen, dass es in 16.3.0 eine neue geben wird, aber ich kann anscheinend keine Möglichkeit finden, Kontextdetails zu lesen
Auf componentDidMount-Lebenszyklus (was für mich sinnvoll ist, um ihn in der Kartenimplementierung zu verwenden).

Gibt es einen Weg, dies zu umgehen?

Question

Hilfreichster Kommentar

Es sollte eine einfache Möglichkeit geben, in Lebenszyklusmethoden auf den Kontext zuzugreifen oder ihn aufzurufen.
Ja, es kann gelöst werden, indem unsere Komponente in eine andere Komponente eingewickelt wird! Aber es fühlt sich mehr nach einer Problemumgehung als nach einer Lösung an.

Ich verstehe, es fühlt sich wie ein zusätzlicher Wrapper an, aber es macht den neuen Kontext schnell . Wenn wir keine expliziten Wrapper-Knoten im Baum hätten, könnten wir Komponenten, die aktualisiert werden müssen, nicht schnell finden.

Wenn Sie im Lebenszyklus auf den Kontext zugreifen müssen, nehmen Sie ihn als Requisite.

class Button extends React.Component {
  componentDidMount() {
    alert(this.props.theme);
  }

  render() {
    const { theme, children } = this.props;
    return (
      <button className={theme ? 'dark' : 'light'}>
        {children}
      </button>
    );
  }
}

export default React.forwardRef((props, ref) => (
  <ThemeContext.Consumer>
    {theme => <Button {...props} theme={theme} ref={ref} />}
  </ThemeContext.Consumer>
));

Dies ist fast die gleiche Anzahl von Zeilen wie bei einer contextTypes -Definition.

Alle 41 Kommentare

Hinzufügen eines Beispiels, bei dem ich versuche, dass dies funktioniert: https://codesandbox.io/s/l20yn296w7

BEARBEITEN: Befolgen Sie die Richtlinien von https://github.com/reactjs/rfcs/blob/master/text/0002-new-version-of-context.md#class -based-api

So kann es mit neuer API erreicht werden.

class BaseMapElement extends React.Component {
  componentDidMount() {
    console.log(this.props.context);
  }

  render() {
    return null;
  }
}

const MapElement = () => (
  <Context.Consumer>
    {context =>
      <BaseMapElement context={context} />
    }
  </Context.Consumer>
)

Die einzige Möglichkeit, über componentDidMount darauf zuzugreifen, besteht darin, in Props umzuleiten.

Bearbeiten: Geändert in componentDidMount

Die Komponente höherer Ordnung, die zu Requisiten umleitet, ist ein gutes Muster, aber in Fällen, in denen die zusätzliche Komponente normalerweise nicht benötigt wird, speichere ich den Kontextwert auf der Komponenteninstanz wie folgt: this.contextValue = value und greife dann in der zu Lebenszyklus-Haken. Es ist ein bisschen hässlich, aber das ist im Allgemeinen in Ordnung, denke ich, da Sie das schönere Hoc-Muster als Optimierung ablehnen

Ich stehe vor dem gleichen Dilemma.
Es sollte eine einfache Möglichkeit geben, in Lebenszyklusmethoden auf den Kontext zuzugreifen oder ihn aufzurufen.
Möglicherweise müssen wir Inhalte initialisieren, Daten überprüfen und abrufen oder sogar beim Aufheben der Bereinigung bereinigen.
Die Leute machen es jetzt mit dem aktuellen vermeintlich kaputten Kontext.
Ja, es kann gelöst werden, indem unsere Komponente in eine andere Komponente eingewickelt wird! Aber es fühlt sich mehr nach einer Problemumgehung als nach einer Lösung an.

Speichern Sie den Kontextwert auf der Komponenteninstanz wie folgt: this.contextValue = value und greifen Sie in den Life-Cycle-Hooks darauf zu

Ich bin mir ziemlich sicher, dass dies im asynchronen Modus unsicher ist. Bitte tu das nicht. cc @acdlite

Ja, es kann gelöst werden, indem unsere Komponente in eine andere Komponente eingewickelt wird! Aber es fühlt sich mehr nach einer Problemumgehung als nach einer Lösung an.

Ich stimme dem zu. Wäre schön, nativ über componentDidMount und componentWillUnmount zuzugreifen, um Dinge initialisieren / bereinigen zu können,

Im Allgemeinen führt die Verwendung von Instanzvariablen, um clever zu sein und den normalen Datenfluss zu betrügen, zu Problemen bei der Asynchronisierung. Tu es einfach nicht. Es ist heute ein bisschen verwirrend, weil Instanz-Vars die einzige Möglichkeit sind, bestimmte Dinge zu tun, wie z. B. Timer. Bevor wir async veröffentlichen, werden wir klarere Empfehlungen veröffentlichen - und eines Tages werden wir eine neue Komponenten-API haben, die sich nicht so sehr auf Instanzen stützt.

tl; dr: Verwenden Sie eine Requisiten-Indirektion. Und machen Sie sich nicht zu viele Sorgen um die zusätzliche Komponente.

Ich bin mir ziemlich sicher, dass dies im asynchronen Modus unsicher ist. Bitte tu das nicht.

Wie wäre das unsicher (und auf welche Weise)? Bei all dem Gerede über den asynchronen Modus ist unklar, was "unsicher" bedeutet. Es fühlt sich an wie ein Boogyman, dessen Verhalten irrational und unvorhersehbar ist, was den Leuten in einem System, das allgemein für sein einfaches, leicht verständliches Datenflussmodell bekannt ist, nicht viel Sicherheit gibt. Ich habe das Gefühl, dass Komponenten wieder im Land vor 0.13 sind, wo sie wieder magische Objekte sind.

Es ist auch leicht zu sagen, "Fügen Sie einfach eine weitere Komponente hinzu", aber das ist oft lästig und führt eine eigene Kategorie von Fehlern und Herausforderungen ein. Ich habe nicht das Gefühl, dass Leute Abstraktionen über eine Reaktions-API erfinden müssen, um "sicher" zu sein.

Entschuldigung ^ Wenn das oben genannte verärgert / wütend klingt, habe ich diesen Ton nicht beabsichtigt! auf einem phhhhooone

Es klang wütend, haha, aber ich verstehe Ihren Standpunkt und teile Ihre Fragen darüber, wie / warum es unsicher sein wird

Es fängt an, sich wie ein Boogyman zu fühlen, dessen Verhalten irrational und unvorhersehbar ist

Es tut mir leid, aber wir arbeiten seit über einem Monat an einer Anleitung mit konkreten Vorschlägen. Bitte geben Sie uns Zeit, um sie als Blog-Beitrag zu sammeln und zu veröffentlichen. Es ist auch schwierig, ohne tatsächliche Alphas zu diskutieren, woran wir auch hart gearbeitet haben.

Wir müssen also entweder gar nichts sagen oder im Voraus vor Dingen warnen, die nicht gut funktionieren. Wir sind auf der Seite der Warnung, aber ich kann sehen, wie es aussehen kann, als würden wir es Ihnen schwerer machen. Ich bin sicher, sobald der Code veröffentlicht ist und Sie damit spielen können, werden Sie sehen, was wir meinen, und es wird sinnvoller sein.

Wie wäre das unsicher (und auf welche Weise)?

Hast du die Gelegenheit bekommen, meinen Vortrag zu sehen ? Dies ist etwas schwer zu erklären, wenn Sie den zweiten Teil nicht gesehen haben, da nicht klar ist, warum wir dies tun. Also bitte ich dich, es dir anzusehen. Ich hoffe, dass mein Vortrag Sie davon überzeugen wird, dass wir eine breite Klasse von Problemen lösen wollen, die React von Anfang an plagten, und dass es sich lohnt, einige Annahmen zu überdenken, an die wir uns gewöhnt haben könnten.

Angenommen, Sie haben den Vortrag gesehen, finden Sie hier eine genauere Erklärung zu diesem speziellen Fall. Um das Rendern wie in der Demo gezeigt aussetzen zu können, muss React zu jedem Zeitpunkt render() aufrufen können, möglicherweise mit unterschiedlichen Requisiten. Wenn Sie beispielsweise this.props und this.state für Requisiten von einem neuen Bildschirm (der geladen wird) festlegen, rufen Sie render , setzen Sie ihn dann aber auf alte this.props und this.state beim Rendern als Reaktion auf eine Interaktion mit der aktuellen Version des Baums (z. B. wenn ich etwas drücke, während der neue Bildschirm geladen wird).

Bei Async lautet die Faustregel: Nur Lebenszyklen wie componentDidMount , componentDidUpdate und componentWillUnmount und Ref-Rückrufe werden zu genau definierten Zeitpunkten mit entsprechenden Requisiten und Status ausgeführt zu dem, was auf dem Bildschirm angezeigt wird. Glücklicherweise haben wir nur wenige andere Lebenszyklen, die nicht genau in dieses Bild passen, und wir führen bessere Alternativen für sie ein ( getDerivedPropsFromState , getSnapshotBeforeUpdate ). Dies wird eine schrittweise Migration sein. Wieder wird alles im Blog-Beitrag stehen.

Nun zur Wurzel dieses Problems. Im asynchronen Modus gibt React keine Garantie dafür, wann und in welcher Reihenfolge die Methode render aufgerufen wird . Das ist wirklich etwas, was React überhaupt nicht garantiert hat - es war einfach jedes Mal die gleiche Reihenfolge. Das Speichern eines Felds in render und das anschließende Lesen in einem Lebenszyklus ist nicht „sicher“, da Sie möglicherweise ein Feld zu dem Zeitpunkt speichern, zu dem React mit dem Namen render mit verschiedenen Requisiten (z. B. für einen hängenden Baum) reagiert ist noch nicht fertig).

Es sollte eine einfache Möglichkeit geben, in Lebenszyklusmethoden auf den Kontext zuzugreifen oder ihn aufzurufen.
Ja, es kann gelöst werden, indem unsere Komponente in eine andere Komponente eingewickelt wird! Aber es fühlt sich mehr nach einer Problemumgehung als nach einer Lösung an.

Ich verstehe, es fühlt sich wie ein zusätzlicher Wrapper an, aber es macht den neuen Kontext schnell . Wenn wir keine expliziten Wrapper-Knoten im Baum hätten, könnten wir Komponenten, die aktualisiert werden müssen, nicht schnell finden.

Wenn Sie im Lebenszyklus auf den Kontext zugreifen müssen, nehmen Sie ihn als Requisite.

class Button extends React.Component {
  componentDidMount() {
    alert(this.props.theme);
  }

  render() {
    const { theme, children } = this.props;
    return (
      <button className={theme ? 'dark' : 'light'}>
        {children}
      </button>
    );
  }
}

export default React.forwardRef((props, ref) => (
  <ThemeContext.Consumer>
    {theme => <Button {...props} theme={theme} ref={ref} />}
  </ThemeContext.Consumer>
));

Dies ist fast die gleiche Anzahl von Zeilen wie bei einer contextTypes -Definition.

Ja, es kann gelöst werden, indem unsere Komponente in eine andere Komponente eingewickelt wird! Aber es fühlt sich mehr nach einer Problemumgehung als nach einer Lösung an.

Ich wollte nur dem zustimmen, was Dan gesagt hat, dass der Ansatz der untergeordneten Funktion / Render-Requisite die offizielle API für den neuen Kontext ist. Verwenden Sie ihn also und lassen Sie React sich Sorgen machen, ob er schnell ist. (Es wird sein!)

Wie wäre das unsicher (und auf welche Weise)?

In den Dokumenten zum Entwurf des

Wir haben einen experimentellen Zweig, der den hier vorgeschlagenen Richtlinien folgt. Kann jemand nachsehen, ob es Sinn macht? https://github.com/commodityvectors/react-mapbox-gl/pull/11

Ich bin mit dieser Bibliothek nicht vertraut, daher weiß ich nicht, ob Leute jemals Refs mit ihren Komponenten verwenden - aber wenn ja, könnte das withContext -Mixin auf dieser PR ein guter Anwendungsfall für die sein neue forwardRef API .

Das macht Sinn. Danke für den Hinweis. Ich werde dieses Problem vorerst schließen.

Ich bin gerade auf dieses Problem gestoßen, weil ich versucht habe zu sehen, ob ich das Gleiche erreichen kann.

Soweit ich das alles beurteilen kann, ist es in der Komponente, die Context.Consumer , nicht möglich, außerhalb der untergeordneten Renderfunktion auf die API zuzugreifen. Ich habe mir etwas ausgedacht, das dies alles ein wenig einfacher machen könnte (würde mich über ein Feedback sehr freuen, wenn dies aus irgendeinem Grund keine gute Praxis ist):

const MapElement = (props) => (
  <Context.Consumer>
    {context =>
      <RunOnLifecycle
        runOnMount={() => { /*use context*/ }}
        runOnUnMount={() => { /*use context*/ }}
        runOnUpdate={(prevProps) => { /*use context - compare prevProps with props */ }}
        { ...props }
      />
    }
  </Context.Consumer>
)

Und diese Hilfskomponente <RunOnLifecycle/> :

export interface IPropsRunOnLifecycle {
  runOnMount?: () => void;
  runOnUpdate?: (prevProps: object) => void;
  runOnUnMount?: () => void;
  children?: JSX.Element | ReactNode;
  [prop: string]: any;
}

export class RunOnLifecycle extends React.Component<IPropsRunOnLifecycle> {
  componentDidUpdate(prevProps, prevState, snapshot) {
    if (this.props.runOnUpdate != null) {
      this.props.runOnUpdate(prevProps);
    }
  }

  componentDidMount() {
    if (this.props.runOnMount != null) {
      this.props.runOnMount();
    }
  }

  componentWillUnmount() {
    if (this.props.runOnUnMount != null) {
      this.props.runOnUnMount();
    }
  }

  render() { return this.props.children || null; }
}

Ich frage mich, ob dies später zu Kopfschmerzen führen wird. Fühlt sich immer noch wie ein ziemlich normaler React an, wenn auch ein bisschen wie ein Hack.

Es gibt einige subtile Unterschiede, die diesen Ansatz zu einer schlechten Idee machen könnten. Wenn beispielsweise MapElement eine Klassenkomponente wäre, die refs verwendet, würden die refs noch nicht festgelegt, wenn der Rückruf runOnMount ausgeführt würde.

😄 Ich würde stattdessen vorschlagen, dafür einen HOC-Ansatz zu verwenden:
https://reactjs.org/docs/context.html#consuming -context-with-a-hoc

Der einzige wirkliche Nachteil bei der Verwendung eines HOC für diese Art von Dingen wurde durch die forwardRef API gemildert:
https://reactjs.org/docs/react-api.html#reactforwardref

Wir haben den Ansatz wie die Reaktionsdokumente und das, was die Leute hier gesagt haben, gewählt. Es funktioniert bisher gut für uns.

https://github.com/commodityvectors/react-mapbox-gl/blob/master/src/Map.js#L63

Es gibt einige subtile Unterschiede, die diesen Ansatz zu einer schlechten Idee machen könnten. Wenn MapElement beispielsweise eine Klassenkomponente wäre, die refs verwendet, würden die refs noch nicht festgelegt, wenn der runOnMount-Rückruf ausgeführt wurde.

Danke für das Feedback @bvaughn . Im Moment verwende ich es lediglich als eine Art Status-Proxy-Komponente, die Dinge zur Benutzeroberfläche hinzufügt / daraus entfernt, je nachdem, was im Kontextbaum bereitgestellt wird. Ein bisschen wie Portale, aber innerhalb des React-Komponentenbaums. Also überhaupt keine Kinder rendern oder mit Refs umgehen.

Ich werde daran denken, wenn ich etwas tun muss, das mit Schiedsrichtern interagiert.

Hallo allerseits,

Ich benötige Kontextdaten in Lebenszyklusmethoden. Nachdem ich die ersten Kommentare gesehen hatte, folgte ich dem HOC-Ansatz und übergab die Kontextdaten als Requisiten.
Alles funktioniert wie erwartet. Aber jetzt möchte ich Unit-Testfälle für die Komponenten schreiben, kann dies aber nicht.

Ich würde es wirklich begrüßen, wenn jemand mitteilen könnte, wie ich Testfälle für dieses Szenario schreiben kann.

Ich benutze Enzym, Enzymadapter-React-16 und Scherz, habe aber einige Probleme damit.

@ AmArArora

In der Firma, für die ich arbeite, machen wir Folgendes (beachten Sie, dies ist möglicherweise nicht der Konsens), exportieren auch die "nackte" Komponente und importieren sie dann in unsere Tests und übergeben die Requisiten manuell.

Z.B

// MyComponent.js
export class MyComponent extends Component { /* ... */ }
export default HOC()(MyComponent)

// MyComponent.spec.js
import { MyComponent } from '...'

// OtherComponents.js
import MyComponent from '...'

Beim Hinzufügen zu dieser Diskussion sind wir auf dasselbe Problem gestoßen und haben dieses https://www.npmjs.com/package/react-context-consumer-hoc erstellt , das mehrere Kontexte verwendet.

Alles funktioniert wie erwartet. Aber jetzt möchte ich Unit-Testfälle für die Komponenten schreiben, kann dies aber nicht.

@AmnArora Warum können Sie keinen

@pgarciacamou Zunächst danke für die schnelle Antwort. Nun, nachdem Sie nichts im Web gefunden und die Abfrage hier gepostet haben. Ich habe die gleiche Lösung gefunden, die Sie erwähnt haben.

Die Testfälle funktionieren jetzt, aber dies scheint eine Problemumgehung zu sein. Ich werde einen Blick auf https://www.npmjs.com/package/react-context-consumer-hoc werfen und mit meinem Team diskutieren.

Vielen Dank. :100:

@bvaughn Die Sache ist früher, als ich Redux für die diver () und instance () verwendet, um die Instanz der Komponente

Bei Verwendung der Kontext-API war jedoch keine dieser Methoden verfügbar.

Und als ich keine dieser Methoden verwendete, wurde der folgende Fehler angezeigt :

Erwischt.

Beides klingt nach Problemen mit der von Ihnen verwendeten Enzyme-Version, die die neue Kontext-API nicht ordnungsgemäß unterstützt. Das ist bedauerlich.

Ich bekam massive Abneigung gegen redux und unistore (viel Codeverschmutzung / zusätzliche bewegliche Teile imo), was mich zu dem folgenden Setup führte, das unseren verschachtelten Komponenten den Zugriff auf einen einzelnen globalen Zustand ermöglicht. Alles andere, was sich nicht im globalen Status befinden sollte (z. B. Texteingabewerte, Umschaltwerte), wird im lokalen Status jeder verschachtelten Komponente gespeichert.

https://github.com/davalapar/session-context

Hallo,

Ist dieses Problem gelöst?

Ich habe ein Szenario, in dem ich 3 Komponenten hatte. Schöpfer, Anzeige, Zellen.
Cell hat meine Renderlogik, die sowohl in Creator als auch in Display verwendet wird.

Derzeit muss ich den Status übergeben, wenn das Element erstellt wird oder angezeigt werden muss. Ich habe Zellen an verschiedenen Orten verwendet, daher muss ich den Status als Requisiten separat übergeben. Ich wollte also den Kontext für den Status verwenden, aber das Problem ist, dass ich den Kontext nur ändern wollte, wenn die Anzeigekomponente bereitgestellt wurde. Können wir dies erreichen, ist Reacts aktuelle Version? (Ich benutze React 16.7)

Es gab einige Kommentare oben, die zeigen, wie auf Context.Consumer -Werte in componentDidMount . Hast du sie probiert? Haben sie aus irgendeinem Grund nicht gearbeitet?

Beachten Sie, dass React 16.6 eine neue contextType API für Klassen hinzugefügt hat, die das Lesen eines neuen Kontexts in componentDidMount erleichtert.

https://reactjs.org/docs/context.html#classcontexttype

Ja, vorausgesetzt, Sie müssen nur einen einzigen Kontext in Ihrer Komponente verwenden - contextType ist eine bequeme Option.

Beachten Sie, dass React 16.6 eine neue contextType API für Klassen hinzugefügt hat, die das Lesen eines neuen Kontexts in componentDidMount erleichtert.

Es tut nicht. Selbst wenn ein einzelner Kontexttyp ausreicht, unterbricht Class.contextType die Vererbung. Gleiches gilt für HOC.

In unseren Dokumenten wird ziemlich explizit empfohlen, Komposition gegenüber Vererbung zu empfehlen, um Code zwischen Komponenten wiederzuverwenden. Darüber hinaus verstehe ich nicht wirklich, was Sie sagen.

Die contextType API macht es definitiv einfach, auf Kontextwerte in componentDidMount zuzugreifen (worum es in diesem Thread geht).

Wir sind in unseren Dokumenten ziemlich explizit darüber, wie man Komposition gegenüber Vererbung empfiehlt ...

Das ist zu breit ...

Der Fall, mit dem ich gerade zu kämpfen habe, ist, dass ich eine Familie von Komponenten mit einer Reihe gemeinsamer Funktionen habe, die zur Unterstützung ihrer Implementierung erforderlich sind. Alles wird durch Vererbung perfekt modelliert, außer ... Kontextbits!

Angesichts der Tatsache, dass ich nur in solchen Situationen mit dem Kontext zu tun habe, ist die Kontext-API ziemlich frustrierend.

... darum geht es in diesem Thread ...

Ja, dieser Kommentar ist etwas unangebracht.

Das Ändern von contextType mit Context Class unterbricht den Redux-Speicher: /

Beachten Sie, dass React 16.6 eine neue contextType-API für Klassen hinzugefügt hat, die das Lesen eines neuen Kontexts in componentDidMount erleichtert.

Ja, vorausgesetzt, Sie müssen nur einen einzigen Kontext in Ihrer Komponente verwenden - contextType ist eine praktische Option.

Gibt es keine Möglichkeit, Kontexte zu erstellen, bevor sie MyCoolComponent.contextType zugewiesen werden?

Ich habe vorerst gelesen, wenn wir eine Komponente wollen, die:

a) Verbrauchen Sie mehrere Kontexte
b) Verwenden Sie Dinge aus diesen Kontexten in anderen Methoden als render

Dies bedeutet, dass wir uns an das beschriebene Muster halten, bei dem der Wrapper den Kontext verbraucht und Requisiten an das Kind weitergibt.

Ich denke, eine ideale Situation wäre, dass ich so etwas schreiben und das Beste aus beiden Welten herausholen könnte (dh mehrere Kontexte, die in der gesamten Klasse verfügbar sind):

MyCoolComponent.contextType =  composeContexts(OneContext, TwoContext, RedContext, BlueContext)

Gibt es eine Möglichkeit, dies zu tun?

Es funktioniert für die Render-Methode, aber nicht für eine andere Methode ... eine Idee?

Sie da.
Gibt es eine Möglichkeit, die neue Kontext-API im Konstruktor einer Klassenkomponente zu verwenden?

Wir migrieren unsere Projekte von v15.x auf v16.x. Eine der Aufgaben besteht darin, die neue Kontext-API zu verwenden
In unserem Projekt verwenden wir CSS-Module + Isomorphic-Style-Loader. Letzterer stellt einige APIs zur Verfügung, um die Komponenten-Stylesheets in DOM einzufügen.

In V15 fügen wir diese APIs in die alte Kontext-API ein und lassen jede Komponente über so etwas abrufen

    class MyComp extends Component {
        static contextTypes = {
                insertCss: PropTypes.func
           }
         ....
         componentWillMount () {
                // insert a style tag for this component
               this.removeCss = this.context.insertCss(myStyles)
         }
    }

In V15 können wir dies in die Komponente WillMount einfügen. Dadurch wird sichergestellt, dass die Komponente vor dem Rendern den richtigen Stil erhält.

In V16 ist die Komponente WillMount jedoch als unsicher markiert und wird in Zukunft nicht mehr unterstützt.
Unsere unmittelbaren Gedanken wären also, unseren Aufruf context.insertCss in den Konstruktor der Komponente einzufügen.

Aus dem Dokument geht jedoch hervor ,

Wenn contextTypes innerhalb einer Komponente definiert ist, erhalten die folgenden Lebenszyklusmethoden einen zusätzlichen Parameter, das Kontextobjekt:

Konstruktor (Requisiten, Kontext)

Diese Verwendung (mit Kontext als zweitem Parameter) wird ebenfalls nicht mehr unterstützt.

Ich habe die neue Kontext-API ausprobiert und MyComp.contextType = StyleContext zugewiesen
Dennoch finde ich, dass ich this.context im Konstruktor undefiniert bekomme.

    class MyComp extends Component {
        static contextType = StyleContext

         constructor (props) {
             super(props)
             console.log(this.context) // undefined
         }

    }

Gibt es eine praktische Anleitung zur Verwendung des Kontexts im Konstruktor?

Irgendein Rat?

Sie da.
Gibt es eine Möglichkeit, die neue Kontext-API im Konstruktor einer Klassenkomponente zu verwenden?

Wir migrieren unsere Projekte von v15.x auf v16.x. Eine der Aufgaben besteht darin, die neue Kontext-API zu verwenden
In unserem Projekt verwenden wir CSS-Module + Isomorphic-Style-Loader. Letzterer stellt einige APIs zur Verfügung, um die Komponenten-Stylesheets in DOM einzufügen.

In V15 fügen wir diese APIs in die alte Kontext-API ein und lassen jede Komponente über so etwas abrufen

    class MyComp extends Component {
        static contextTypes = {
                insertCss: PropTypes.func
           }
         ....
         componentWillMount () {
                // insert a style tag for this component
               this.removeCss = this.context.insertCss(myStyles)
         }
    }

In V15 können wir dies in die Komponente WillMount einfügen. Dadurch wird sichergestellt, dass die Komponente vor dem Rendern den richtigen Stil erhält.

In V16 ist die Komponente WillMount jedoch als unsicher markiert und wird in Zukunft nicht mehr unterstützt.
Unsere unmittelbaren Gedanken wären also, unseren Aufruf context.insertCss in den Konstruktor der Komponente einzufügen.

Aus dem Dokument geht jedoch hervor ,

Wenn contextTypes innerhalb einer Komponente definiert ist, erhalten die folgenden Lebenszyklusmethoden einen zusätzlichen Parameter, das Kontextobjekt:

Konstruktor (Requisiten, Kontext)

Diese Verwendung (mit Kontext als zweitem Parameter) wird ebenfalls nicht mehr unterstützt.

Ich habe die neue Kontext-API ausprobiert und MyComp.contextType = StyleContext zugewiesen
Dennoch finde ich, dass ich this.context im Konstruktor undefiniert bekomme.

    class MyComp extends Component {
        static contextType = StyleContext

         constructor (props) {
             super(props)
             console.log(this.context) // undefined
         }

    }

Gibt es eine praktische Anleitung zur Verwendung des Kontexts im Konstruktor?

Irgendein Rat?

Sie können dies tun, anstatt contextType zu verwenden

class MyComponent extends React.Component {
   render(){
       const {
         //props including context props
       } = this.props;
       return(<View />);
   }
};

const withContext = () => (
  <MyContext.Consumer>
    { (contextProps) => (<MyComponent {...contextProps}/>)}
  </MyContext.Consumer>
);

export default withContext;

Für alle, die wie ich Schwierigkeiten haben, es außerhalb Ihrer Renderfunktion zu verwenden, verwenden Sie einfach Folgendes in Ihrer Unterkomponente:

useContext ()

Zum Beispiel:

const context = useContext(yourContext)

MainComponent.Subcomponent = () => {
 const context = useContext(context)

  useEffect(()=> {
    console.log(context)
  })
}
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen