Syftet med den här artikeln är att ge dig tips som kan hjälpa dig och ditt team i era React Native-projekt. Några av dessa tips är strikt React Native-relaterade, medan andra i allmänhet är mer mobilutvecklingsorienterade. Så låt oss gå rakt in i det!
- Bry dig inte om Expo
Du bör aldrig använda Expo i ett seriöst projekt, av flera skäl.
För det första sker inte hela byggprocessen lokalt, utan i Expos moln, vilket innebär liten eller ingen kontroll och potentiella serverproblem under byggandet. För det andra lägger du till ytterligare ett lager av komplexitet i ditt projekt, vilket saktar ner det och ökar appstorleken.
Viktigast av allt är att inbyggda iOS/Android-moduler, som du säkert kommer att behöva vid något tillfälle, inte stöds. De enda inbyggda modulerna som är tillgängliga för dig är de som tillhandahålls av Expo SDK.
Förr eller senare kommer du att nå en punkt där du måste mata ut Expo-appen till en vanlig React Native-app, så du kan lika gärna inte slösa bort din tid och starta projektet på rätt sätt ändå. - Använd ESLint
Att använda en linter på alla projekt är ett måste, särskilt för ett vilt språk som JavaScript. ESLint är ett fantastiskt tillägg som är extremt enkelt att installera, konfigurera och använda, så se till att inkludera det i ditt projekt redan från början. Om du inte håller med om några av reglerna kan du alltid inaktivera dem i .eslintrc konfigurationsfil, men att ha någon form av kvalitetskontroll av koden kommer att hjälpa dig och ditt team oerhört mycket i det långa loppet. - Ta bort alla loggar från dina releasebyggen
Att ha många console.log satser kan göra din app långsammare, särskilt om du använder loggningsbibliotek som redux-logger. Se till att inaktivera alla loggar (manuellt eller med ett skript) när du gör en release-version. - Använd Flexbox
Detta borde verkligen vara en självklarhet, men tyvärr har jag sett React Native-kod som använder absolut elementpositionering istället för flexbox, vilket bryter layouten och inte ger någon återanvändbarhet alls. Oavsett vilka designkrav du har är det nästan en självklarhet att använda flexbox alltid det korrekta svaret. För dig som kommer från webb-bakgrund: Flexbox i React Native fungerar nästan exakt likadant som dess CSS-motsvarighet, den viktiga skillnaden är att flexDirection Standardvärdet är kolumn i stället för rad i React Native. - Namnge dina stilobjekt på ett konsekvent sätt
Om din rotvy har ett stilobjekt med namnet behållareoch sedan använda det namnet för alla rotvyer i projektet. Om din skicka-knapp har ett stilobjekt med namnet submitButtonså håll dig till det och använd inte saveButton, submitBtn eller submit för andra fall. - Tänk på smarta och dumma komponenter
Detta är extremt viktigt för alla React Native-projekt eftersom att klassificera dina komponenter som smarta eller dumma hjälper dig att organisera ditt projekt logiskt och även återanvända dina komponenter bättre.
Smarta komponenter, även kallade klassbaserade eller containerkomponenter , handlar om hur saker fungerar. Det innebär att de håller tillståndet, hämtar data från API:et, gör det mesta av beräkningen, håller reda på livscykelmetoderna om det behövs, tillhandahåller data till andra komponenter och har ingen styling inkluderad. Dumma komponenter, även kallade funktionella eller presentationskomponenter, bryr sig om hur saker och ting ser ut. De tar helt enkelt emot data (props) via överordnade komponenter och visar dem för användaren. De har vanligtvis inget tillstånd och minimal logik, och innehåller all styling. De är mycket återanvändbara eftersom de tillhandahåller en enkel funktionalitet baserad på indata. - Använd ternära operatorer på ett koncist sätt
Skriva färg = fel ? 'red': 'gray' är kort och gott.
Skriva färg = fel ? (id === myID) ? 'red' : 'black' : 'gray' inte är det. Ternära operatorer kan bidra till att minska antalet rader i din kod, men använd dem aldrig i ett bo eftersom logiken blir svår att läsa. - Missbruka inte zIndex
Använd zIndex endast när du måste. Om du till exempel vill lägga över en <Text> över en <Image>är zIndex fel sätt att göra det på. Du bör använda <ImageBackground> komponent istället. En bra tumregel är att om du tycker att du gör din kod onödigt komplicerad med många zIndex-egenskaper, så har du förmodligen rätt. Go Gå tillbaka till ruta ett och tänk om när det gäller din layout. - setState() är asynkron
Detta måste vara ett av de vanligaste nybörjarfelen i React Native. Även om ändring av tillståndet för en komponent orsakar en omrendering, om du skriver något som setState({ username: ‘somevalue’ })och försök sedan läsa detta.tillstånd.användarnamn i nästa kodrad kommer du inte att läsa rätt värde, eftersom setState() är en asynkron operation. Använd await setState({ användarnamn }) för att undvika detta problem. - Du kan skicka redux-åtgärder från andra åtgärder
En åtgärd behöver inte vara begränsad till endast en API-begäran eller en typ av datamanipulation. Alla åtgärder kan skickas från en annan åtgärd, från samma eller en annan fil. Det låter uppenbart men kan förbises. - Lämna inte känsliga data i din app
Detta inkluderar API-nycklar, API-hemligheter, projekt-ID, kundhemligheter, domäner och alla andra data som är för känsliga för att förvaras i appen. Förvara alla dessa på servern, inte i ditt projekt. - Hantera dina bildresurser på rätt sätt
Använd beskrivande bildnamn, eftersom namn login_button_disabled.png är mycket tydligare och mer återanvändbart än inloggningsknapp_grå.png. Tillhandahåll alltid @1x, @2x, och @3x för att kunna hantera olika skärmdensiteter på både iOS och Android. Om dimensionerna på dina bildtillgångar är för små eller inte är korrekt märkta kan du få suddiga bilder i din app, vilket gör att din app ser väldigt oprofessionell ut. Om du å andra sidan vill minska filstorleken på alla dina bilder på ett enkelt sätt utan att förlora någon kvalitet, kan du använda program som ImageOptim. - Använd destrukturering av objekt
Ingen vill se this.props.navigation.state.params.användarnamn överallt. Så använd destrukturering av objekt. Det gör koden lättare att läsa och förstå. Och du kan (och bör) också använda det i funktionsparametrar, så istället för const MyComponent = (props) => { du kan skriva const MyComponent = ({username, userID }) => {.
Du måste bestämma när du ska använda destrukturering och när du inte ska göra det, men för det mesta är det en bra idé. Det är inte en bra idé om det i onödan gör små funktioner mycket större, eller om det skapar konflikter mellan variabelnamn. Om du till exempel har variabler som this.props.id och this.state.id, destrukturering skulle reducera båda variablerna till samma namn idvilket inte är bra. - Torrt överallt
Om jag skulle nämna en programmeringsprincip som ligger till grund för allt annat inom programvaruutveckling, så skulle det vara Upprepa inte dig själv princip. När du skriver samma kod två gånger ska du göra om den till något som kan återanvändas. Även om det inte är helt samma sak men liknande, är det värt att överväga att abstrahera det. Skapa dina egna återanvändbara komponenter och verktygsmetoder. Du kommer att vara glad att du gjorde det senare, eftersom det kommer att öka din effektivitet och göra ditt projekt modulärt. Om alla dina knappar ser likadana ut, med en specifik teckenstorlek, färg och kantradie, är det naturligtvis en bra idé att skapa en wrapper-komponent. Men stanna inte där. Gör omslagskomponenter för allt som du använder upprepade gånger i din app. Har du textknappar? Gör en återanvändbar komponent <TextButton> vars enda syfte är att linda in <TouchableOpacity> och <Text>. Har du flera bildknappar? Skapa en komponent <ImageButton> som omsluter <TouchableOpacity> och <Image>. Himlen är gränsen! - Om att använda externa bibliotek
Om det finns ett bibliotek som uppfyller dina behov och det inte är övergivet, är det bättre att använda det istället för att uppfinna hjulet på nytt. Du sparar din dyrbara utvecklingstid för något annat. Du måste dock göra en del forskning om de bibliotek du planerar att använda. Är det aktivt och underhålls regelbundet? Har det ett bra betyg? Är det väl testat? Har det många problem? Har det stöd för både iOS och Android? En tumregel är att om det tar mer tid att lära sig använda ett externt bibliotek än att göra allt själv, bör du hålla dig borta från det.
Ibland vill du ändra något i ett externt bibliotek. Gör inte redigera den direkt i node_modules/ mapp. Den mappen ska ändå ignoreras av versionshanteringen, så om du ändrar koden direkt kommer dina teamkollegor inte att se dina ändringar. Dessutom kan en npm update åtgärden kommer att skriva över dina ändringar. Lösningen är att antingen förgrena det ursprungliga arkivet och länka ditt projekt till ditt eget arkiv där du gjorde ändringarna (och till och med göra en PR till den ursprungliga författaren om du vill hjälpa till!), eller om biblioteket är mycket litet (en fil) kan du kopiera / klistra in det som en komponent i ditt eget projekt och sedan redigera det lokalt. - Använd Live Reloading, Hot Reloading och Inspector
Var och en av dessa React Native-funktioner är extremt användbara, så se till att använda alla tre. Live Reloading sparar dig tid som du skulle spendera på att manuellt uppdatera appen, Hot Reloading sparar dig tid som det tar att designa om en skärm som inte är lättillgänglig i din app, och Inspector sparar dig massor av console.log-satser. - Använd async/await-syntax, men inte blint
Om du är en React Native-utvecklare använder du förmodligen redan async/await-syntax. Det ser rent ut och det räddar dig från callback-helvetet. Tänk dock på att denna syntax gör effektivt din asynkrona kod synkronså innan du använder det, fråga dig själv: Behöver du verkligen det här? Finns det något du behöver göra parallellt med din tidigare kod? Om så är fallet kan du behöva tänka om. Om du har flera API-anrop som inte på något sätt är beroende av varandra är det bästa du kan göra att skapa ett promise för vart och ett av dessa asynkrona anrop, lägga dem alla i en array och köra Promise.all() på det. Detta resulterande "grupp"-löfte kommer att avslutas så snart alla löften inuti är klara, vilket definitivt är mycket snabbare än att köra varje begäran en efter en. - Ändring av innehållet i en state array/map kommer inte att orsaka en omrenderingOm du har en tillståndsvariabel som är en hashmapp kommer inte själva variabeln att ändras om du ändrar dess innehåll, så
render() kommer inte att anropas. För att undvika detta måste du göra en djup kopia av variabeln, till exempel med hjälp av _.cloneDeep() funktion från lodash bibliotek. - Åsidosättande av stil
Om du behöver åsidosätta ett befintligt stilobjekt eller ändra stilen dynamiskt kan du göra det enkelt med den här syntaxen:
<View style={[ containerStyle, myStyle ]}>...</View>,
där myStyle är det stilobjekt som åsidosätter containerStyle. - Se upp för iOS säkerhetsområde
För att din app ska se bra ut på alla iOS-enheter måste du packa in varje skärm i din app i en säker områdesvy för att undvika att vyerna blockeras. Ännu bättre är att du kan skapa en omslagskomponent för React Natives <SafeAreaView>där du kan lägga till allt annat som du behöver ha på varje skärm i din app, till exempel OfflineNotis indikator till exempel. - Använd inte TouchableWithoutFeedback om du inte har en bra anledning
Enligt den officiella React Native-dokumentationen ska alla element som reagerar på tryck ha en visuell återkoppling när de vidrörs. Tänk på detta när du skapar dina gränssnittselement och använd <TouchableWithoutFeedback> sparsamt. - Grundlig testning av nya komponenter för kantfall
Om din nya komponent har en etikett för användarnamn ska du prova den med ett absurt långt användarnamn och se om den passar bra eller om den går utanför layouten. Det är också en bra tid att ställa in ellipsizeMode och numberOfLines för <Text> komponent om det behövs. Samma princip gäller för alla komponenter. Tortera den med olika data och se hur den beter sig innan du avslutar den, eftersom felsökning av layoutbrott kommer att ta mycket mer tid senare. - Använd mekanismer för felrapportering och logga misslyckade användningsfall
Du bör absolut ha någon form av mekanism för felrapportering, till exempel Crashlytics. Men utöver det är det mycket användbart att logga alla misslyckade användningsfall någonstans. Du kan använda tjänster som Amplitude, din egen backend eller något helt annat. Händer det ofta att dina användare anger sitt användarnamn istället för e-postadress på inloggningsskärmen? Eller kanske rapporterar de inloggningsfel i din app, men i själva verket vet de inte ens sina egna inloggningsuppgifter? Jag har sett allt detta hända – allt är möjligt. Logga så mycket du kan så att du kan spara tid för alla, men också för att se var dina användare ofta gör misstag och använda den informationen för att förbättra din app. - Gör API-anrop i componentDidMount()
Det är välkänt att du aldrig någonsin ska hämta data i render() metod, men componentWillMount() är inte heller rätt plats att göra det på. För det första är det en äldre metod, vilket i sig borde vara ett tillräckligt skäl för att inte använda den. För det andra kommer det att inte förhindra ytterligare render() anropet, så det blir inte heller några prestandaförbättringar. Det sista skälet är att du alltid måste hantera standardtillstånd för att kunna rendera komponenten med tomma tillståndsvärden. Så lägg alla dina API-anrop i componentDidMount() för att alltid ha ett korrekt flöde av data och rendering. - Tänk på bakåtkompatibilitet
Ibland tas en specifik funktion bort, eller så införs någon annan avgörande förändring, som till exempel ett annat JSON-svar på en API-slutpunkt. Var alltid medveten om att vissa av dina användare inte kommer att uppdatera appen till en ny version direkt, och att deras gamla version kan krascha eller agera på något annat oväntat sätt.
Detta avslutar del 1 av den här artikeln. Ta en paus, ta lite ☕ och när du är redo fortsätter du till Del 2! 😀
Du får också gärna dela med dig av dina egna tips i kommentarerna. 🧐
Trevlig kodning!