Website-Suche

reactjs - Wie übergebe ich sauber eine React-Komponente an eine andere Komponente tief in der Komponenten-Hierarchie?


Ich habe eine React + Redux + Typescript-Anwendung, die aus einer Karte, mehreren Diagrammen und einer Reihe von Modaldialogen besteht (einer davon ist ein Druckformular). Die Präsentations- und Container-Komponenten sind wie folgt zusammengesetzt.

┌──────────────────────────────────────────┐  
│ app.tsx                                  │
│  ┌─────────────────────────────────────┐ │
│  │ modalsContainer.tsx                 │ │
│  │  ┌────────────────────────────────┐ │ │ 
│  │  │ printModal.tsx                 │ │ │
│  │  │  ┌───────────────────────────┐ │ │ │
│  │  │  │ printFormContainer.tsx    │ │ │ │
│  │  │  │    const mergeProps(...); │ │ │ │
│  │  │  └───────────────────────────┘ │ │ │
│  │  └────────────────────────────────┘ │ │ 
│  └─────────────────────────────────────┘ │
│  ┌─────────────────────────────────────┐ │
│  │ mapContainer.tsx                    │ │
│  │  ┌────────────────────────────────┐ │ │ 
│  │  │ map.tsx                        │ │ │
│  │  │     private map:EsriMap        │ │ │
│  │  └────────────────────────────────┘ │ │ 
│  └─────────────────────────────────────┘ │ 
│  ┌─────────────────────────────────────┐ │
│  │ dashboard.tsx                       │ │
│  │  ┌────────────────────────────────┐ │ │ 
│  │  │ charts.tsx                     │ │ │
│  │  └────────────────────────────────┘ │ │ 
│  └─────────────────────────────────────┘ │ 
└──────────────────────────────────────────┘

Das Druckformular ermöglicht es dem Benutzer, die Diagramme und die Karte als PDF zu drucken. Es wird eine Webanfrage gestellt, damit der Bericht basierend auf den ausgewählten Diagrammen und der aktuellen Karte gedruckt wird. Die Logik dafür ist in const mergeProps(...); unten eingerichtet:

const mergeProps = (stateProps: any, dispatchProps: any, ownProps: any): any => {
    return {
        fetchReport: (title: string, summary: string, includeMap: boolean) => {
            if(includeMap) {
               // fetch map image
               // need access to mapcontainer /map / esrimap here
            }

            // ... fetch report ...
        },
        close: dispatchProps.close
    };
};

Das funktioniert größtenteils, aber ich habe das Kartenbild noch nicht im Bericht eingefügt. Um ein Bild der Karte zu erstellen, muss ich eine PrintTask ausführen. Einer der Parameter für die Druckaufgabe ist das Esri-Kartenobjekt. Allerdings habe ich von mergeProps aus keinen Zugriff auf die MapContainer- oder Map-Komponenten. Wenn ich darauf Zugriff hätte, könnte ich eine Print():Promise<any>-Funktion hinzufügen, um die Aufgabe auszuführen und das Bild zurückzugeben.

Ich möchte wirklich globale Variablen vermeiden. Andere Funktionen in der Zukunft könnten ebenfalls Zugriff auf die Karte erfordern. Ich möchte auch vermeiden, Komponenten so tief durch die Stack-Ebene als Props weiterzugeben. Ich habe ein wenig über Context gelesen, aber das scheint stark nicht empfohlen zu sein.

Wie übergebe ich eine Komponente sauber an eine andere tief im Stapel?

Antwort #1

Ein paar Gedanken:

Zuerst ist es im Allgemeinen eine schlechte Idee, irgendetwas Nicht-Serialisierbares (wie eine Komponente oder eine Funktion) in den Redux-Zustand zu legen (siehe https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state).

Zweitens, warum wird die Callback-Logik derzeit in mergeProps definiert? Diese Option sollte wirklich nur als letzte Notlösung dienen. Es ist besser, Callbacks separat zu definieren und sie an die Komponente zu übergeben. Ich habe einige Diskussionen und Beispiele dazu unter http://blog.isquaredsoftware.com/2016/10/idiomatic-redux-why-use-action-creators/.

Daran anschließend glaube ich, dass der einfachste Ansatz darin bestehen würde, eine separate Callback-Funktion zu definieren, die die benötigten Flags und das EsriMap-Objekt als Parameter nimmt, und diese Funktion als Prop an die Map-Komponente zu übergeben.