Einige Erfahrung im Aufbau des React Native-Projektframeworks

Einige Erfahrung im Aufbau des React Native-Projektframeworks

React Native ist ein plattformübergreifendes Framework zur Entwicklung mobiler Anwendungen, das im April 2015 von Facebook als Open Source veröffentlicht wurde. In nur ein bis zwei Jahren haben viele Unternehmen dieses Framework unterstützt und übernommen, um die mobilen Anwendungen ihres Unternehmens zu erstellen.
React Native ermöglicht Ihnen eine vollständig konsistente Entwicklungserfahrung auf Basis von Javascript und React zum Erstellen nativer Apps der Spitzenklasse.

Projektrahmen und Projektstruktur

1. Im Projekt verwendeter Technologie-Stack

React Native, React Hook, Typescript, Immer, Tslint, Jest usw.

Sie sind alle recht verbreitet, deshalb werde ich sie nicht im Detail vorstellen.

2. Die Datenverarbeitung verwendet useContext+useReducer im React-Hook

Die Idee entspricht Redux, es ist relativ einfach zu verwenden und für weniger komplexe Geschäftsszenarien geeignet.

const HomeContext = createContext<IContext>({
  Status: Standardstatus,
  Versand: () => {}
});
const ContextProvider = ({ urlQuery, pageCode }: IProps) => {
  const initState = getInitState(urlQuery, pageCode);
  const [Status, Versand]: [IHomeState, IDispatch] = useReducer(homeReducer, initState);

  zurückkehren (
    <HomeContext.Provider-Wert={{ Status, Dispatch }}>
      <HomeContainer />
    </HomeContext.Provider>
  );
};
const HomeContainer = () => {
const { Versand, Status } = useContext(HomeContext);
...

3. Die Projektstruktur ist wie folgt

|-Seite1
    |-handler // Reine Funktion zur Verarbeitungslogik, muss durch UT abgedeckt werden|-container // Daten, Verhalten und Komponenten integrieren|-component // Reine UI-Komponente, zeigt Inhalt und Benutzerinteraktion an, verarbeitet keine Geschäftslogik|-store // Die Datenstruktur darf 3 Ebenen nicht überschreiten und die Ebene kann durch externe Referenzen und redundante Felder reduziert werden|-reducer // Immer verwenden, um neue Daten zurückzugeben (unveränderliche Daten)
    |-...
|-Seite2
|-...

Vorgaben im Projekt

1. Seite

Das gesamte Projekt ist eine mehrseitige Anwendung und die grundlegendste Aufteilungseinheit ist die Seite.

Jede Seite hat einen entsprechenden Store, nicht das gesamte Projekt verwendet einen Store. Die Gründe dafür sind folgende:

  • Die Logik jeder Seite ist relativ unabhängig
  • Jede Seite kann als Projekteintrag verwendet werden
  • Kombinieren Sie den RN-Seitenlebenszyklus, um Daten zu verarbeiten (vermeiden Sie Dateninitialisierung, Caching und andere Probleme).

Externe Vorgänge auf jeder Seite werden in der Seitenkomponente definiert

  • Seitensprunglogik
  • Nach dem Rollback zu verarbeitende Ereignisse
  • Welche Speicherdaten müssen betrieben werden?
  • Welche Leistungen müssen beantragt werden etc.

Die Hauptfunktion der Seitenkomponente

Basierend auf einem eigenen Business-Modul werden alle abstrahierbaren externen Abhängigkeiten und externen Interaktionen im Code dieser Komponente konzentriert.

Für Entwickler ist es praktisch, beim Schreiben von Logik und bei der Fehlersuche zwischen Seiten bestimmte Codes entsprechend bestimmter Seiten + Datenquellen genau zu lokalisieren.

2. Reduzierstück

In früheren Projekten konnten Reducer einige Datenverarbeitungen, Benutzerverhalten, Protokollpunkte, Seitensprünge und andere Codelogik beinhalten.

Denn beim Schreiben des Codes stellen Entwickler fest, dass der Reducer der Endpunkt einer bestimmten Verarbeitungslogik ist (nach dem Aktualisieren des Status ist das Ereignis beendet), was sich für diese Aufgaben sehr gut eignet.

Mit der Wartung des Projekts und der Iteration der Anforderungen nimmt die Größe des Reduzierers weiter zu.

Aufgrund der fehlenden Organisation und der riesigen Menge an Code wäre es schwierig, den Code anzupassen.

Es ist vorstellbar, wie mühselig es für Sie wäre, ein solches Projekt aufrechtzuerhalten.

Zu diesem Zweck wurden einige Subtraktionen am Code im Reducer vorgenommen:

  • Ändern Sie nur die Statusdaten im Reduzierer
  • Verwenden Sie die Produkte von Immer, um unveränderliche Daten zu generieren
  • Überflüssige Einzelfelder ändern, integrieren und die den Seitenverhalten entsprechenden Aktionen auflisten

Die Hauptfunktion des Reduzierers

Fassen Sie alle Szenarien der Betriebsdaten auf der Seite in aufzählbarer Form zusammen.

Zusätzlich zu seinen eigenen Funktionen, die für das React-Framework geeignet sind, ist es mit bestimmten Attributen zum Lesen der Geschäftslogik ausgestattet, sodass die gesamte Datenverarbeitungslogik auf der Seite grob gelesen werden kann, ohne auf UI-Komponenten angewiesen zu sein.

// Vermeiden Sie doppeltes Versenden und das Definieren zu vieler Einzelfeld-Aktualisierungsfälle
// Nach der Integration dieser Logik wird sie mit dem Verhalten auf der Seite verknüpft, was zum Verständnis und Lesen des Falls beiträgt. EFHListAction.updateSpecifyQueryMessage:
    returniere produzieren(Zustand, (Entwurf: IFHListState) => {
        draft.specifyQueryMessage = Nutzlast als Zeichenfolge;
        Entwurf.showSpecifyQueryMessage = true;
    });    
Fall EFHlistAction.updateShowSpecifyQueryMessage:
    returniere produzieren(Zustand, (Entwurf: IFHListState) => {
        draft.showSpecifyQueryMessage = Nutzlast als Boolescher Wert;
    });

3. Handler

Hier führen wir zunächst das Konzept einer reinen Funktion ein:

Eine Funktion heißt reine Funktion, wenn ihr Rückgabewert nur von ihren Parametern abhängt und sie bei der Ausführung keine Nebenwirkungen hat.

Abstrahieren Sie so viel Logik wie möglich in reine Funktionen und packen Sie diese in Handler:

  • Deckt mehr Geschäftslogik ab
  • Nur reine Funktionen
  • UT-Abdeckung ist erforderlich

Die Hauptfunktion des Handlers

Verantwortlich für die logische Verarbeitung in Szenarien wie Datenquelle zum Speichern, Container zur Komponente, Versand zum Reduzierer usw.

Als Speicherort für logische Verarbeitungsfunktionen in verschiedenen Szenarien ist die gesamte Datei nicht an der Zuordnungsbeziehung im Seitenprozess beteiligt. Jede Funktion kann wiederverwendet werden, solange sie die Verwendungsszenarien ihrer Eingabe und Ausgabe erfüllt, und wird hauptsächlich in Containerdateien verwendet.

Exportfunktion getFilterAndSortResult(
  Flugliste: IFlightInfo[],
  filterList: IFilterItem[],
  filterShare: Boolesch,
  filterOnlyDirect: Boolesch,
  Sortiertyp: EFlightSortType
) {
  wenn (!isValidArray(flugliste)) {
    zurückkehren [];
  }

  const sortFn = getSortFn(sortType);
  const Ergebnis = Flugliste.Filter(v => doFilter(v, Filterliste, Filteranteil, 1, FilternurDirekt)).Sort(SortFn);

  Ergebnis zurückgeben;
}
beschreiben(getFilterAndSortResult.name, () => {
  test('getFilterAndSortResult', () => {
    Erwarte (getFilterAndSortResult (Flugliste, Filterliste, falsch, EFlightSortType.PriceAsc)). gleich (FilterSortResult);
  });
});

4. Behälter

Wie aus dem obigen Projektstrukturdiagramm ersichtlich ist, verfügt jede Seite über einen Basiscontainer als Zentrum der Datenverarbeitung.

Unter diesem Basiscontainer wird jeder Untercontainer entsprechend unterschiedlicher Module definiert:

  • Lebenszyklusverarbeitung (einige asynchrone Vorgänge müssen während der Initialisierung ausgeführt werden)
  • Stellt Datenquellen zum Rendern von Komponenten bereit
  • Definieren Sie die Verhaltensfunktion auf der Seite

Die Hauptfunktion von Container

Im gesamten Projekt sollten die Konvergenzpunkte verschiedener Daten, Benutzeroberflächen und Benutzerverhalten so weit wie möglich von den entsprechenden Modulen getrennt werden, um ein übermäßiges Codevolumen und Wartungsschwierigkeiten zu vermeiden.

Die Definition des Containers sollte durch die auf der Seite angezeigten Module abstrahiert werden. Beispielsweise Head-Container, Inhaltscontainer, Footer-Container und andere gängige Unterteilungsmethoden.

Einige relativ unabhängige Module auf einigen Seiten sollten auch ihre entsprechenden Container erstellen, um die zugehörige Logik zu aggregieren, z. B. das Modul zur Couponvergabe, das Modul zum Benutzerfeedback usw.

Achten Sie besonders auf die Verhaltensfunktion

  • Verhaltensweisen, die mehreren Containern gemeinsam sind, können direkt im Basiscontainer platziert werden
  • Das Aktionsbeispiel (setAction) im obigen Architekturdiagramm ist eine weitere Verhaltenswiederverwendung, die je nach bestimmten Szenarien angewendet wird.

Praktisch zum Lesen des Codes: Die schwebende Anzeigelogik von Modul A und die Reihenfolge, in der Module generiert werden, wenn Modul B verwendet wird, müssen zuerst Modul A und dann Modul B die Methode von A verwenden.

  • Definieren Sie Datenpunkte und Benutzerverhaltenspunkte
  • Aufruf der Seitensprungmethode (Seite-->Basiscontainer-->Untercontainer)
  • Andere Nebenwirkungen des Verhaltens
const OWFlightListContainer = () => {
    // Daten über Context abrufen const { state, dispatch } = useContext(OWFlightListContext);
    ...

    // Countdown für Timeout beim ersten Laden useOnce(overTimeCountDown);
    ...
    
    // Benutzer klickt auf Sortieren const onPressSort = (lastSortType: EFlightSortType, isTimeSort: boolean) => {
        // Referenziert die Funktion getNextSortType im Handler const sortType = getNextSortType(lastSortType, isTimeSort);
        Dispatch ({Typ: EOWFlightListAction.updateSortType, Nutzlast: Sortiertyp});
        
        // Punktvergrabener Vorgang logSort(state, sortType);
    };
    
    // Rendern der Anzeigekomponente return <.../>;
}

Zusammenfassung

Von einfach zu codieren bis einfach zu lesen
Im Laufe des Projektes werden zahlreiche Vorgaben definiert, um neben der Funktionsrealisierung auch die Wartung durch das Projektpersonal zu erleichtern.

  • Die Seitenkomponente enthält seitenbezogene externe Abhängigkeiten
  • Reducer zählt alle Ereignisse auf, die auf Seitendaten einwirken
  • Der Handler integriert die Verarbeitung der Geschäftslogik und stellt die Qualität des Projekts mit reiner Funktionsimplementierung und UT-Abdeckung sicher.
  • Die Verhaltensfunktion im Container definiert alle Ereignisse im Zusammenhang mit Benutzeroperationen und zeichnet die eingebetteten Daten auf
  • Vermeiden Sie die Verarbeitung der Geschäftslogik in Componet, führen Sie nur die UI-Anzeige durch, reduzieren Sie die UI-Automatisierungsfälle und erhöhen Sie die UT-Fälle

Es ist relativ einfach, die Spezifikation zu definieren. Um ein Projekt erfolgreich aufrechtzuerhalten, kommt es eher darauf an, dass die Teammitglieder beharrlich an der Prämisse festhalten, einen Konsens zu erreichen.

Teilen Sie einige praktische Funktionen

Wert basierend auf dem Objektpfad abrufen

/**
 * Holen Sie sich den Wert basierend auf dem Objektpfad* @param target {a: { b: { c: [1] } } }
 * @param Pfad 'abc0'
 */
Exportfunktion getVal(Ziel: beliebig, Pfad: Zeichenfolge, Standardwert: beliebig = undefiniert) {
  lass ret = Ziel;
  let-Schlüssel: Zeichenfolge | undefiniert = '';
  const PfadList = Pfad.split('.');

  Tun {
    Schlüssel = Pfadliste.Shift();
    wenn (ret && Schlüssel !== undefiniert && Typ von ret === 'Objekt' && Schlüssel in ret) {
      ret = ret[Schlüssel];
    } anders {
      ret = undefiniert;
    }
  } während (Pfadliste.Länge && ret !== undefiniert);

  return ret === undefiniert || ret === null? Standardwert: ret;
}

//DEMO
const errorCode = getVal(Ergebnis, 'rstlist.0.type', 0);

Lesen Sie gemäß den Konfigurationsinformationen

// Bei der Anbindung an die Außenwelt werden oft feste Strukturen und skalierbare Datenlisten definiert. // Um ​​sich an solche Verträge anzupassen und eine bessere Lesbarkeit und Wartung zu ermöglichen, werden folgende Funktionen zusammengefasst. export const GLOBAL_NOTE_CONFIG = {
  2: 'Rückerstattung',
  3: 'Sortierungstyp',
  4: "Featureschalter"
};

/**
 * Holen Sie sich gemäß der Konfiguration den Wert in attrList und geben Sie die Daten des JSON-Objekttyps zurück * @private
 * @Mitglied von DetailService
 */
Exportfunktion getNoteValue<T>(
  noteList: Array<T> | nicht definiert | null,
  Konfiguration: { [_: Zeichenfolge]: Zeichenfolge },
  Schlüsselname: Zeichenfolge = "Typ"
) {
  const ret: { [_: Zeichenfolge]: T | Array<T> } = {};

  wenn (!isValidArray(noteList!)) {
    Rückkehr ret;
  }

  //@ts-ignorieren
  noteList.forEach((Hinweis: beliebig) => {
    const typeStr: string = (('' + note[keyName]) als unbekannt) als string;

    if (!(typeStr in config)) {
      zurückkehren;
    }

    if (Hinweis === undefiniert || Hinweis === null) {
      zurückkehren;
    }

    const key = konfiguration[typeStr];

    // Wenn mehrere Werte vorhanden sind, zum Array-Typ wechseln if (ret[key] === undefined) {
      ret[Schlüssel] = Notiz;
    } sonst wenn (Array.isArray(ret[key])) {
      (ret[Taste] als T[]).push(Hinweis);
    } anders {
      const first = ret[Schlüssel];
      ret[Schlüssel] = [erste, Notiz];
    }
  });

  Rückkehr ret;
}

//DEMO
// Anwendbar auf die Wertelogik einiger extern definierter erweiterbarer Notizknotenlisten const { sortType, featureSwitch } = getNoteValue(list, GLOBAL_NOTE_CONFIG, 'ntype');


Sortieren von Arrays mit mehreren Bedingungen

/**
 * Holt die zum Sortieren verwendete Sortierfunktion * @param fn Vergleichsfunktion für Elemente gleichen Typs, true bedeutet Sortierpriorität */
Exportfunktion getSort<T>(fn: (a: T, b: T) => boolean): (a: T, b: T) => 1 | -1 | 0 {
  Rückgabewert (a: T, b: T): 1 | -1 | 0 => {
    sei ret = 0;

    wenn (fn.call(null, a, b)) {
      ret = -1;
    } sonst wenn (fn.call(null, b, a)) {
      ret = 1;
    }

    gib ret als 0 zurück;
  };
}

/**
 * Mehrfachsortierung */
Exportfunktion getMultipleSort<T>(arr: Array<(a: T, b: T) => 1 | -1 | 0>) {
  Rückgabewert (a: T, b: T) => {
    lass tmp;
    sei i = 0;

    Tun {
      tmp = arr[i++](a, b);
    } während (tmp === 0 und i < arr.length);

    temporär zurückgeben;
  };
}

//DEMO
const ageSort = getSort(Funktion(a, b) {
  returniere a.Alter < b.Alter;
});

const nameSort = getSort(Funktion(a, b) {
  gibt a.name < b.name zurück;
});

const sexSort = getSort(Funktion(a, b) {
  gebe a.Geschlecht und !b.Geschlecht zurück;
});

//Die Reihenfolge der Beurteilungsbedingungen kann angepasst werden const arr = [nameSort, ageSort, sexSort];

const ret = data.sort(getMultipleSort(arr));

Oben sind einige Details meiner Erfahrungen beim Erstellen des React Native-Projektframeworks aufgeführt. Weitere Informationen zum Erstellen des React Native-Projektframeworks finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Einrichten der React-Native-Umgebung und grundlegende Einführung
  • VSCode erstellt eine React Native-Umgebung
  • Verwenden Sie den Win10+Android+Yoshi Android-Emulator, um eine ReactNative-Entwicklungsumgebung zu erstellen
  • React Native-Schritte zum Erstellen einer Entwicklungsumgebung
  • Tutorial zur Einrichtung der React Native-Umgebung
  • React Native erstellt iOS-Entwicklungsumgebung
  • Detaillierte Erklärung, wie Sie Jest zum Testen von React Native-Komponenten in Ihrem Projekt verwenden

<<:  So erstellen Sie einen neuen Benutzer in CentOS und aktivieren die Schlüsselanmeldung

>>:  Beispiel für die MySQL-Volltext-Fuzzy-Suche nach der Methode MATCH AGAINST

Artikel empfehlen

So ändern Sie den Hostnamen in Linux

1. Den aktuellen Hostnamen anzeigen [root@fangjia...

JavaScript-Timer zum nahtlosen Scrollen von Bildern

In diesem Artikel wird der spezifische JavaScript...

Vue realisiert Click-Flip-Effekt

Verwenden Sie Vue, um einfach einen Click-Flip-Ef...

Beispiel für utf8mb4-Sortierung in MySQL

Allgemeine utf8mb4-Sortierregeln in MySQL sind: u...

Attribute im Vue V-For-Loop-Objekt

Inhaltsverzeichnis 1. Werte innerhalb von Schleif...

25 CSS-Frameworks, Tools, Software und Vorlagen geteilt

Kobold-Kuh herunterladen CSS-Fussel herunterladen...

XHTML-Erste-Schritte-Tutorial: Einfache Webseitenerstellung

Erstellen Sie Ihre erste Webseite in einer Minute...

Detaillierte Erklärung zur Installation der PHP-Curl-Erweiterung unter Linux

Dieser Artikel beschreibt, wie man die PHP-Curl-E...

So optimieren Sie den MySQL-Deduplizierungsvorgang maximal

Inhaltsverzeichnis 1. Clevere Verwendung von Indi...

CSS zum Erzielen des Effekts einer rotierenden Flip-Card-Animation

Die CSS-Animation des rotierenden Flip-Effekts, d...

Warum wird in React nicht empfohlen, einen Index als Schlüssel zu verwenden?

1. Vergleichen Sie den alten virtuellen DOM mit d...