8 pràctiques en reacció que bloquejaran la vostra sol·licitud

Bloc

8 pràctiques en reacció que bloquejaran la vostra sol·licitud

8 pràctiques en reacció que bloquejaran la vostra sol·licitud

Molts de nosaltres ens hem enamorat de la biblioteca de reaccions per diversos motius. Això llauna ser increïblement indolor per crear interfícies d'usuari interactives complexes. La major part de tot plegat és poder compondre components damunt d’un altre sense trencar-ne d’altres.



I és sorprenent que fins i tot gegants de les xarxes socials com Facebook, Instagram i Pinterest en facin un ús intensiu alhora que creaven una experiència d’usuari perfecta amb enormes API com Google Maps.

Si actualment creeu una aplicació amb react o esteu pensant en utilitzar react per a propers projectes, aquest tutorial és per a vosaltres. Espero que aquest tutorial us ajudi vostè en el vostre viatge per fer que les aplicacions reaccionin també exposant algunes implementacions de codi que hauríeu de pensar dues vegades.



Sense més preàmbuls, aquí teniu 8 pràctiques en reacció que afectaran la vostra aplicació en el futur:

1. Comprovació descuidada d'objectes buits en la renderització

Una cosa que feia fa molt temps en els dies daurats quan es representaven els components de manera condicional és comprovar si les dades s’han omplert en objectes mitjançant Object.keys. I si hi hagués dades, el component continuaria representant-se si la condició passa:



const SomeComponent = ({ children, items = {}, isVisible }) => ( {Object.keys(items).length ? ( ) : (

Data has not been received

)} )

Pretenem que hem cridat alguna API i que hem rebut articles com a objecte en algun lloc de la resposta. Dit això, al principi pot semblar perfectament bé. El tipus esperat de articles és un objecte, de manera que estaria perfectament bé utilitzar-lo Object.keys amb ell. Al cap i a la fi, nosaltres va fer inicialitzar elements a un objecte buit com a mecanisme de defensa si mai aparegués un error que el convertís en un valor fals.

convertir JSON a CSV Python pandes

Però no hem de confiar en el servidor tornar sempre la mateixa estructura . Què passa si els articles es converteixen en una matriu en el futur? Object.keys(items) faria no caure però retornaria una sortida estranya com ['0', '1', '2']. Com creieu que reaccionaran els components que es representen amb aquestes dades?

Però això ni tan sols és el pitjor. La pitjor part del fragment és que si articles es va rebre com a nul valor als accessoris, llavors items ni tan sols s’iniciarà al valor predeterminat que heu proporcionat.

I llavors l'aplicació es bloquejarà abans que comenci a fer qualsevol altra cosa :

'TypeError: Cannot convert undefined or null to object at Function.keys () at yazeyafabu.js:4:45 at https://static.jsbin.com/js/prod/runner-4.1.7.min.js:1:13924 at https://static.jsbin.com/js/prod/runner-4.1.7.min.js:1:10866'

Una vegada més, si us plau, tingueu cura!

2. Declaració dels paràmetres predeterminats sobre nul

Una vegada vaig ser culpable de passar una bona quantitat de temps depurant alguna cosa similar a això:

const SomeComponent = ({ items = [], todaysDate, tomorrowsDate }) => { const [someState, setSomeState] = useState(null) return (

Today is {todaysDate}

And tomorrow is {tomorrowsDate}
{items.map((item, index) => ( {item.email} ))} ) } const App = ({ dates, ...otherProps }) => { let items if (dates) { items = dates ? dates.map((d) => new Date(d).toLocaleDateString()) : null } return ( ) }

Dins del nostre component d'aplicació, si les dates acaben sent falses, s'inicialitzarà amb nul.

Si sou com jo, els nostres instints ens indiquen que els elements s’han d’inicialitzar per defecte a una matriu buida si es tractés d’un valor fals. Però la nostra aplicació es bloquejarà quan les dates siguin falses perquè els elements són nuls. Què ?

Els paràmetres de funció predeterminats permeten inicialitzar paràmetres anomenats amb valors predeterminats si no es passa cap valor o no definit.

En el nostre cas, tot i que null és fals, segueix sent un valor.

Per tant, la propera vegada que establiu un valor per defecte a nul , assegureu-vos de pensar-ho dues vegades quan feu això. Simplement podeu inicialitzar un valor a una matriu buida si aquest és el tipus esperat del valor.

3. Agafar propietats amb claudàtors

De vegades, la manera com s’agafen les propietats pot influir en el comportament de l’aplicació. Si us pregunteu quin és aquest comportament, l’aplicació es bloqueja. Aquí teniu un exemple de cerques d'objectes amb claudàtors:

const someFunction = function() { return { names: ['bob', 'joe'], foods: ['apple', 'pineapple'], } } const obj = someFunction() const names = obj['names'] console.log(names) // result: ['bob', 'joe']

En realitat, són casos d'ús vàlids al 100% i no hi ha res de dolent a més de ser més lents que les cerques de claus d'objecte.

De totes maneres, el problema real comença a agafar-se a la vostra aplicació com més aprofundiu amb les cerques:

const someFunction = function() { return { names: ['bob', 'joe'], foods: ['apple', 'pineapple'], } } const obj = someFunction() const names = obj['names'] console.log(names) // result: ['bob', 'joe'] console.log(names.joe) // result: undefined

Tot i això, és una mica difícil explicar la gravetat d’aquesta pràctica sense un exemple real. Així que presentaré un exemple del món real. L'exemple de codi que estic a punt de mostrar-lo s'ha extret d'un dipòsit que data d'avui fa 8 mesos. Per protegir part de la privadesa que va originar aquest codi, he canviat el nom de gairebé totes les variables, excepte la de el disseny de codis, la sintaxi i l'arquitectura es van mantenir exactament iguals :

import { createSelector } from 'reselect' // supports passing in the whole obj or just the string to correct the video type const fixVideoTypeNaming = (videoType) => { let video = videoType // If video is a video object if (video && typeof video === 'object') { const media = { ...video } video = media.videoType } // If video is the actual videoType string if (typeof video === 'string') { // fix the typo because brian is an idiot if (video === 'mp3') { video = 'mp4' } } return video } /* ------------------------------------------------------- ---- Pre-selectors -------------------------------------------------------- */ export const getOverallSelector = (state) => state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.total .overall export const getSpecificWeekSelector = (state, props) => state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.weekly[ props.date ] /* ------------------------------------------------------- ---- Selectors -------------------------------------------------------- */ export const getWeeklyCycleSelector = createSelector( getSpecificWeekSelector, (weekCycle) => weekCycle || null, ) export const getFetchingTotalStatusSelector = createSelector( (state) => state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.total .fetching, (fetching) => fetching, ) export const getFetchErrorSelector = createSelector( (state) => state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.total .fetchError, (fetchError) => fetchError, )

fixVideoTypeNaming és una funció que extreu el tipus de vídeo en funció del valor que es transmet com a arguments. Si l’argument és un vídeo objecte , extreurà el tipus de vídeo del fitxer .videoType propietat. Si es tracta d'una cadena, la persona que truca ha passat al videoType perquè puguem ometre el primer pas. Algú ha trobat que el tipus de vídeo .mp4 la propietat s'havia escrit malament en diverses àrees de l'aplicació. Per obtenir una solució temporal ràpida al problema, fixVideoTypeNaming es va utilitzar per corregir aquest error tipogràfic.

Ara, com alguns de vosaltres hauríeu imaginat, l’aplicació es va crear amb redux (d’aquí la sintaxi).

I per utilitzar aquests selectors, els importaríeu per utilitzar-los en un component d’ordre superior de connexió per connectar un component per escoltar aquesta part de l’estat.

const withTotalCount = (WrappedComponent) => { class WithTotalCountContainer extends React.Component { componentDidMount = () => { const { total, dispatch } = this.props if (total == null) { dispatch(fetchTotalVideoTypeCount()) } } render() { return } } WithTotalCountContainer.propTypes = { fetching: PropTypes.bool.isRequired, total: PropTypes.number, fetchError: PropTypes.object, dispatch: PropTypes.func.isRequired, } WithTotalCountContainer.displayName = `withTotalCount(${getDisplayName( WrappedComponent, )})` return connect((state) => { const videoType = fixVideoTypeNaming(state.app.media.video.videoType) const { fetching, total, fetchError } = state.app.media.video[ videoType ].options.total return { fetching, total, fetchError } })(WithTotalCountContainer) }

Component de la IU:

const TotalVideoCount = ({ classes, total, fetching, fetchError }) => { if (fetching) return const hasResults = !!total const noResults = fetched && !total const errorOccurred = !!fetchError return ( {noResults && 'No Results'} {hasResults && `$${formatTotal(total)}`} {errorOccurred && 'An error occurred.'} ) }

El component rep tots els accessoris que el HOC li transmet i mostra informació seguint les condicions adaptant-se a les dades proporcionades pels accessoris. En un món perfecte, estaria bé. En un món no perfecte, això ho faria temporalment estar bé.

Si tornem al contenidor i observem la forma en què els selectors seleccionen els seus valors, és possible que haguem plantat una bomba de temps que espera a l'espera d'una oportunitat oberta per atacar:

export const getOverallSelector = (state) => state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.total .overall export const getSpecificWeekSelector = (state, props) => state.app[fixVideoTypeNaming(state.app.media.video.videoType)].options.weekly[ props.date ]

Quan es desenvolupa cap S'està implementant una mena d'aplicació, pràctiques habituals per garantir un nivell més alt de confiança i una disminució dels errors durant el flux de desenvolupament proves entremig per assegurar-vos que l'aplicació funciona de la manera prevista.

Tanmateix, en el cas d’aquests fragments de codi, si no es proven, l’aplicació voluntat caiguda en el futur si no es gestiona abans.

Per un, state.app.media.video.videoType és quatre nivells profunds a la cadena. Què passa si un altre desenvolupador va cometre un error per error quan se li va demanar que solucionés una altra part de l'aplicació i state.app.media.video esdevé sense definir ? L'aplicació es bloquejarà perquè no pot llegir la propietat videoType of indefinit .

A més, si hi havia un altre problema d’error tipogràfic amb un fitxer videoType i fixVideoTypeNaming no s’actualitza per acomodar-ho juntament amb el mp3 problema, l'aplicació corre el risc d'un altre bloqueig involuntari que ningú hagués pogut detectar tret que usuari real troba el problema. I en aquell moment ja ho seria massa tard .

I la seva mai una bona pràctica per suposar que l'aplicació mai no trobarà errors com aquests. Siusplau, tingues compte!

4. Comprovació descuidada de si existeixen matrius abans de la renderització

Aquesta pot ser una situació molt similar a la del número 3, però les matrius i els objectes s'utilitzen sovint indistintament que mereixen les seves pròpies seccions.

Si teniu el costum de fer això:

render() { const { arr } = this.props return ( {arr && arr.map()...} ) }

A continuació, assegureu-vos que, com a mínim, tingueu proves unitàries per mantenir els vostres ulls en tot moment o manejar arr correctament abans de passar-la al mètode de renderització, o bé l'aplicació es bloquejarà si arr esdevé un objecte literal . Per descomptat, el && l'operador ho considerarà com veritat i intentar-ho .map l'objecte literal que acabarà fallant tota l'aplicació.

Per tant, tingueu present això. Estalvieu la vostra energia i frustracions per problemes majors que mereixen més atenció especial. ;)

5. No utilitzeu Linter

Si no utilitzeu cap tipus de liner mentre desenvolupeu aplicacions o simplement no sabeu què són, permeteu-me que expliqui una mica per què són útils per al desenvolupament.

El linter que utilitzo per ajudar-me en el meu flux de desenvolupament és ESLint, una eina molt coneguda de linting per a JavaScript que permet als desenvolupadors descobrir problemes amb el seu codi sense ni tan sols executar-los.

Aquesta eina és tan útil que pot actuar com a semi-mentor, ja que ajuda a corregir els vostres errors en temps real, com si algú us estigués assessorant. Fins i tot descriu per què el vostre codi pot ser dolent i us suggereix què heu de fer per substituir-los!

Aquí teniu un exemple:

eslint

El més interessant d’eslint és que, si no us agraden determinades regles o no esteu d’acord amb algunes, podeu desactivar-ne algunes de manera que ja no apareguin com a advertències / errors tan lentament a mesura que aneu desenvolupant. Tot el que et faci feliç , dret?

6. Desestructuració en representar llistes

He vist això passar a diverses persones en el passat i no sempre és un error fàcil de detectar. Bàsicament, quan teniu una llista d’elements i renderitzareu un munt de components per a cada un de la llista, l’error que pot aparèixer a la vostra aplicació és que si arriba un moment en què un dels elements a la llista no hi ha un valor que espereu que sigui, és possible que l'aplicació es bloquegi si no sap gestionar el tipus de valor.

Aquí teniu un exemple:

const api = { async getTotalFrogs() { return { data: { result: [ { name: 'bob the frog', tongueWidth: 50, weight: 8 }, { name: 'joe the other frog', tongueWidth: 40, weight: 5 }, { name: 'kelly the last frog', tongueWidth: 20, weight: 2 }, ], }, } }, } const getData = async ({ withTongues = false }) => { try { const response = await api.getTotalFrogs({ withTongues }) return response.data.result } catch (err) { throw err } } const DataList = (props) => { const [items, setItems] = useState([]) const [error, setError] = useState(null) React.useEffect(() => { getData({ withTongues: true }) .then(setItems) .catch(setError) }, []) return ( {Array.isArray(items) && ( {items.map(({ name, tongueWidth, weight }) => ( Name: {name} Width of their tongue: {tongueWidth}cm Weight: {weight}lbs ))} )} {error && You received an error. Do you need a linter?} ) }

granotes1

El codi funcionaria perfectament. Ara bé, si mirem la trucada API i en lloc de retornar-la:

const api = { async getTotalFrogs() { return { data: { result: [ { name: 'bob the frog', tongueWidth: 50, weight: 8 }, { name: 'joe the other frog', tongueWidth: 40, weight: 5 }, { name: 'kelly the last frog', tongueWidth: 20, weight: 2 }, ], }, } }, }

Què passa si d'alguna manera es produïa un problema amb la manera com es gestionava el flux de dades quan es produïa una condició inesperada al client API i, en canvi, tornava aquesta matriu?

const api = { async getTotalFrogs() { return { data: { result: [ { name: 'bob the frog', tongueWidth: 50, weight: 8 }, undefined, { name: 'kelly the last frog', tongueWidth: 20, weight: 2 }, ], }, } }, }

La vostra aplicació es bloquejarà perquè no sap com gestionar-ho:

Uncaught TypeError: Cannot read property 'name' of undefined at eval (DataList.js? [sm]:65) at Array.map () at DataList (DataList.js? [sm]:64) at renderWithHooks (react-dom.development.js:12938) at updateFunctionComponent (react-dom.development.js:14627)

Per tant, per evitar que l'aplicació falli, podeu establir un objecte predeterminat a cada iteració:

{ items.map(({ name, tongueWidth, weight } = {}) => ( Name: {name} Width of their tongue: {tongueWidth}cm Weight: {weight}lbs )) }

I ara, els vostres usuaris no hauran de fer judicis sobre la vostra tecnologia i experiència si no veuen que una pàgina es bloqueja al davant:

granotes2

Tanmateix, tot i que l'aplicació ja no es bloqueja, us recomano anar més enllà i gestionar els valors que falten, com ara retornar nuls per a elements sencers que tinguin problemes similars, ja que de totes maneres no hi ha dades.

7. No investigar prou sobre allò que implementareu

Un error crucial que he comès en el passat va ser confiar excessivament en les aportacions de cerca que havia implementat, confiar en les meves opinions massa aviat durant el joc.

Què vull dir amb això? Bé, no és l'entrada de cerca component amb qui confiava massa. El component hauria d’haver estat fàcil tasca ... i va ser així.

El veritable culpable d'un problema que es va produir amb tota la funcionalitat de cerca va ser el s’inclouen caràcters a les consultes .

Quan enviem paraules clau com a consultes a una API de cerca, no sempre és suficient pensar que totes les tecles que escriu l’usuari són vàlides, tot i que per aquest motiu estiguin al teclat.

Assegureu-vos al 100% que una expressió regular així funcioni de la manera prevista i eviteu deixar de banda els caràcters no vàlids que puguin bloquejar l'aplicació:

const hasInvalidChars = /^.*?(?=[+^#%&$*:?/\[]\)(]).*$/g.test( inputValue, )

Aquest exemple és l’expressió regular establerta més actualitzada per a una API de cerca.

Això és el que abans era:

const hasInvalidChars = /^.*?(?=[+^#%&$*:?/\[])(]).*$/g.test( inputValue, ) const callApi = async (keywords) => { try { const url = `https://someapi.com/v1/search/?keywords=${keywords}/` return api.searchStuff(url) } catch (error) { throw error } }

Com podeu veure la barra inclinada / falta, i això va provocar el bloqueig de l'aplicació. si aquest caràcter s’acaba enviant a una API per cable, endevineu quina API creu que serà l’URL?

A més, no confiaria el 100% de la meva confiança en els exemples que trobeu a Internet. Moltes d’elles no són solucions completament provades i no hi ha realment un estàndard per a la majoria de casos d’ús quan es tracta d’expressions regulars.

8. No restringir les mides de les entrades de fitxers

Restringir la mida dels fitxers que seleccionen els usuaris és una bona pràctica perquè la majoria de les vegades no necessiteu un fitxer reduïdament gran quan es pugui comprimir d’alguna manera sense perdre signes notables de reducció de qualitat.

set vs map js

Però hi ha una raó més important per la qual restringir les mides a un límit determinat és una bona pràctica. A la meva empresa, hem observat que els usuaris en el passat de vegades es congelaven mentre s'estan penjant les seves imatges. No tothom té un Alienware 17 R5 al seu poder, de manera que heu de tenir en compte determinades circumstàncies dels vostres usuaris.

A continuació, es mostra un exemple de restringir els fitxers a un límit de 5 MB (5.000.000 de bytes):

import React, { useState, useEffect } from 'react' const useUploadStuff = () => { const [files, setFiles] = useState([]) // Limit the file sizes here const onChange = (e) => { const arrFiles = Array.from(e.target.files) const filesUnder5mb = arrFiles.filter((file) => { const bytesLimit = 5000000 if (file.size > bytesLimit) { // optionally process some UX about this file size } return file.size { if (files.length) { // do something with files } }, [files]) return { files, onChange, } } const UploadStuff = () => { const { onChange } = useUploadStuff() return (

Hi

) } export default UploadStuff

No voleu que els usuaris pengin videojocs quan se suposa que carreguen documents.

Conclusió

I això conclou el final d’aquest post. Gràcies per llegir!

#react #javascript # best practice