Gelecekte Uygulamanızı Çökecek 8 React Uygulaması – JSManifest

Gelecekte Uygulamanızı Çökecek 8 React Uygulaması – JSManifest

Birçoğumuz çeşitli nedenlerle tepki kitaplığına aşık olduk. BT Yapabilmek karmaşık etkileşimli kullanıcı arayüzleri oluşturmak için inanılmaz derecede acısız olun. Tüm bunların en büyük kısmı, diğer bileşenleri bozmadan bileşenleri üst üste oluşturabilmektir.

Ve sosyal medya devlerinin bile Facebook, Instagram ve Pinterest yaptı bunların yoğun kullanımı gibi devasa API’lerle kusursuz bir kullanıcı deneyimi yaratırken Google Haritalar .

Şu anda tepki kullanarak bir uygulama oluşturuyorsanız veya gelecek projeler için tepki kullanmayı düşünüyorsanız, bu eğitim tam size göre. Umarım bu eğitim yardımcı olur sen iki kez düşünmeniz gereken birkaç kod uygulamasını ortaya çıkararak harika tepki uygulamaları yapma yolculuğunuzda.

Lafı fazla uzatmadan, Gelecekte Uygulamanızı Çöktürecek 8 Tepki Uygulaması:

1. Varsayılan Parametreleri Null Üzerinden Bildirme

bu konuyu bir sekilde bahsetmiştim önceki makale, ama bu, kasvetli bir Cuma günü dikkatsiz bir geliştiriciyi kandırabilecek o tüyler ürpertici “kaçırmalardan” biri! Sonuçta, uygulamalar çöküyor şaka değil–herhangi bir tür çökme, doğru şekilde ele alınmazsa, herhangi bir zamanda para kaybına neden olabilir.

Bir zamanlar buna benzer bir hata ayıklamak için çok zaman harcamaktan suçluydum:

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

  return (
    <div>
      <h2>Today is {todaysDate}</h2>
      <small>And tomorrow is {tomorrowsDate}</small>
      <hr />
      {items.map((item, index) => (
        <span key={`item_${index}`}>{item.email}</span>
      ))}
    </div>
  )
}

const App = ({ dates, ...otherProps }) => {
  let items
  if (dates) {
    items = dates ? dates.map((d) => new Date(d).toLocaleDateString()) : null
  }

  return (
    <div>
      <SomeComponent {...otherProps} items={items} />
    </div>
  )
}

Uygulama bileşenimizin içinde, tarihler yanlış çıkarsa, null ile başlatılacaktır.

Benim gibiyseniz, içgüdülerimiz bize, eğer bir falsey değeri ise, öğelerin varsayılan olarak boş bir diziye başlatılması gerektiğini söyler. Ancak, öğeler boş olduğu için tarihler yanlış olduğunda uygulamamız çökecek. Ne?

Varsayılan işlev parametreleri, herhangi bir değer veya tanımsız geçirilmezse, adlandırılmış parametrelerin varsayılan değerlerle başlatılmasına izin verir!

Bizim durumumuzda, null falsey olsa bile, yine de bir değerdir!

Yani bir dahaki sefere varsayılan bir değer ayarladığınızda hükümsüz, bunu yaparken iki kere düşünmeyi unutma. Değerin beklenen türü buysa, yalnızca boş bir diziye bir değer başlatabilirsiniz.

2. Köşeli Parantezlerle Tutunma Özellikleri

Bazen mülklerin ele geçirilme şekli, uygulamanın davranışını etkileyebilir. Bu davranışın ne olduğunu merak ediyorsanız, uygulama çöküyor. Köşeli parantezler ile nesne arama gerçekleştirmeye bir örnek:

const someFunction = function() {
  return {
    names: ['bob', 'joe'],
    foods: ['apple', 'pineapple'],
  }
}

const obj = someFunction()
const names = obj['names']

console.log(names)

Bunlar aslında %100 geçerli kullanım durumlarıdır ve bunların dışında gerçekten yanlış bir şey yoktur. nesne anahtarı aramalarından daha yavaş olmak.

Her neyse, aramalarda daha derine indikçe asıl sorun uygulamanızda ortaya çıkmaya başlar:

const someFunction = function() {
  return {
    names: ['bob', 'joe'],
    foods: ['apple', 'pineapple'],
  }
}

const obj = someFunction()
const names = obj['names']

console.log(names)


console.log(names.joe)

Ancak, gerçek dünyadan bir örnek olmadan bu uygulamanın ciddiyetini açıklamak biraz zor. Bu yüzden gerçek dünyadan bir örnek getireceğim. Size göstermek üzere olduğum kod örneği, bugünden 8 ay öncesine dayanan bir depodan alınmıştır. Bu kodun kaynaklandığı mahremiyetin bir kısmını korumak için, hemen hemen her değişkeni yeniden adlandırdım, ancak kod tasarımı, sözdizimi ve mimari tamamen aynı kaldı:

import { createSelector } from 'reselect'


const fixVideoTypeNaming = (videoType) => {
  let video = videoType

  
  if (video && typeof video === 'object') {
    const media = { ...video }
    video = media.videoType
  }

  
  if (typeof video === 'string') {
    
    if (video === 'mp3') {
      video = 'mp4'
    }
  }

  return video
}



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
  ]



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,
)

fixVideoTypeAdlandırma argüman olarak iletilen değere göre video türünü çıkaran bir işlevdir. Argüman bir video ise nesnevideo türünü .videoType Emlak. Bu bir dizeyse, ilk adımı atlayabilmemiz için arayan kişi videoType’a iletilir. Birisi, videoType’ın .mp4 özelliği, uygulamanın çeşitli alanlarında yanlış yazılmıştı. Sorunla ilgili hızlı bir geçici düzeltme için, fixVideoTypeAdlandırma bu yazım hatasını düzeltmek için kullanıldı.

Şimdi bazılarınızın tahmin edebileceği gibi, uygulama şu şekilde oluşturuldu: redux (dolayısıyla sözdizimi).

Ve bu seçicileri kullanmak için, onları bir bağlamak durum dilimini dinlemek için bir bileşen eklemek için daha yüksek dereceli bileşen.

const withTotalCount = (WrappedComponent) => {
  class WithTotalCountContainer extends React.Component {
    componentDidMount = () => {
      const { total, dispatch } = this.props
      if (total == null) {
        dispatch(fetchTotalVideoTypeCount())
      }
    }

    render() {
      return <WrappedComponent {...this.props} />
    }
  }

  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)
}

Kullanıcı Arayüzü Bileşeni:

const TotalVideoCount = ({ classes, total, fetching, fetchError }) => {
  if (fetching) return <LoadingSpinner />
  const hasResults = !!total
  const noResults = fetched && !total
  const errorOccurred = !!fetchError

  return (
    <Typography
      variant="h3"
      className={classes.root}
      error={!!fetched && !!fetchError}
      primary={hasResults}
      soft={noResults || errorOccurred}
      center
    >
      {noResults && 'No Results'}
      {hasResults && `$${formatTotal(total)}`}
      {errorOccurred && 'An error occurred.'}
    </Typography>
  )
}

Bileşen, HOC’nin kendisine ilettiği tüm propları alır ve proplardan verilen verilerden uyarlanarak koşulları takip eden bilgileri görüntüler. Mükemmel bir dünyada, bu iyi olurdu. Mükemmel olmayan bir dünyada, bu geçici iyi ol.

Konteynere geri dönersek ve seçicilerin değerlerini seçme biçimlerine bakarsak, aslında açık bir saldırı fırsatı bekleyen bir saatli bomba yerleştirmiş olabiliriz:

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
  ]

geliştirirken hiç uygulama türü, daha yüksek düzeyde güven sağlamak için yaygın uygulamalar ve geliştirme akışı sırasında azalan hatalar uygulanıyor testler Uygulamanın amaçlandığı gibi çalıştığından emin olmak için arada.

Ancak bu kod parçacıkları söz konusu olduğunda, test edilmezlerse uygulama niyet erken ele alınmazsa gelecekte çökebilir.

Bir kişi için, durum.app.media.video.videoType dır-dir dört Zincirin derinliklerinde seviyeler. Ya başka bir geliştirici, uygulamanın başka bir bölümünü düzeltmesi istendiğinde yanlışlıkla bir hata yaptıysa ve durum.app.media.video olur Tanımsız? Uygulama, mülkü okuyamadığı için çökecek videoTürü tanımsız.

Ayrıca, başka bir yazım hatası sorunu varsa, video türü ve fixVideoTypeAdlandırma ile birlikte bunu karşılamak için güncellenmedi mp3 Sorun, uygulama, bir hata olmadıkça kimsenin algılayamayacağı başka bir kasıtsız çökme riskiyle karşı karşıyadır. gerçek kullanıcı konuya rastlar. Ve o zamana kadar olurdu çok geç.

Ve Onun asla Uygulamanın asla böyle hatalarla karşılaşmayacağını varsaymak için iyi bir uygulama. Lütfen dikkatli ol!

3. Render Yaparken Boş Nesneleri Dikkatsizce Kontrol Etme

Bileşenleri koşullu olarak oluştururken altın günlerde uzun zaman önce yaptığım bir şey, Object.keys. Ve eğer veri olsaydı, koşul geçerse bileşen işlemeye devam ederdi:

const SomeComponent = ({ children, items = {}, isVisible }) => (
  <div>
    {Object.keys(items).length ? (
      <DataTable items={items} />
    ) : (
      <h2>Data has not been received</h2>
    )}
  </div>
)

Bazı API’leri çağırdığımızı ve aldığımızı varsayalım. öğeler yanıtta bir yerde bir nesne olarak. Bununla birlikte, bu ilk başta tamamen iyi görünebilir. Beklenen tür öğeler bir nesnedir, bu yüzden kullanmak tamamen iyi olur Object.keys Bununla birlikte. Sonuçta, biz yaptı Öğeleri, onu falsey değerine dönüştüren bir hata ortaya çıkarsa, savunma mekanizması olarak boş bir nesneye başlatın.

Ama sunucuya güvenmemeliyiz her zaman aynı yapıyı döndür. Öğeler gelecekte bir dizi haline gelirse ne olur? Object.keys(items) istemek çarpmamak ama gibi garip bir çıktı döndürürdü ["0", "1", "2"]. Bu verilerle oluşturulan bileşenlerin nasıl tepki vereceğini düşünüyorsunuz?

Ama bu en kötü kısmı bile değil. Snippet’teki en kötü kısım, eğer öğeler olarak alındı hükümsüz sahnedeki değer, sonra items sağladığınız varsayılan değere bile başlatılmayacak!

Ve o zaman uygulamanız başka bir şey yapmaya başlamadan çökecek:

"TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    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"

Tekrar, lütfen dikkatli olun!

4. Oluşturmadan Önce Dizilerin Var Olup Olmadığını Dikkatsizce Kontrol Etme

Bu, #3 ile çok benzer bir durum olabilir, ancak diziler ve nesneler, kendi bölümlerini hak ettikleri için oldukça sık birbirinin yerine kullanılır.

Bunu yapma alışkanlığınız varsa:

render() {
  const { arr } = this.props
  return (
    <div>
      {arr && arr.map()...}
    </div>
  )
}

Ardından, gözlerinizi her zaman bu kodda tutmak veya işlemek için en azından birim testleriniz olduğundan emin olun. arr render yöntemine geçmeden önce doğru şekilde, aksi takdirde uygulama çökecektir arr olur nesne değişmezi. tabii ki && operatör olarak kabul edecektir doğru ve denemek .harita tüm uygulamayı çökertecek olan nesne değişmezi.

Bu yüzden lütfen bunu aklınızda bulundurun. Enerjinizi ve hayal kırıklıklarınızı daha fazla özel ilginizi hak eden daha büyük sorunlara saklayın! 😉

5. Linter Kullanmamak

Uygulama geliştirirken herhangi bir tür linter kullanmıyorsanız veya bunların ne olduğunu bilmiyorsanız, geliştirmede neden yararlı oldukları hakkında biraz bilgi vermeme izin verin.

Geliştirme akışımda bana yardımcı olması için kullandığım linter ESLintgeliştiricilerin kodlarıyla ilgili sorunları çalıştırmadan bile keşfetmelerine olanak tanıyan, JavaScript için çok bilinen bir astarlama aracıdır.

Bu araç o kadar kullanışlıdır ki, sanki biri size rehberlik ediyormuş gibi, hatalarınızı gerçek zamanlı olarak düzeltmenize yardımcı olduğu için yarı mentorunuz gibi davranabilir. O bile kodunuzun neden kötü olabileceğini açıklar ve bunları değiştirmek için ne yapmanız gerektiğini önerir!

İşte bir örnek:

Eslint’in en havalı yanı, belirli kuralları beğenmiyorsanız veya bazılarına katılmıyorsanız, belirli kuralları basitçe devre dışı bırakabilirsiniz, böylece geliştirirken artık linting uyarıları/hataları olarak görünmezler. seni mutlu eden ne varsaSağ?

6. Listeleri Oluştururken İmha Etme

Bunun geçmişte birkaç kişinin başına geldiğini gördüm ve tespit edilmesi her zaman kolay bir hata değildir. Temel olarak, bir öğe listeniz olduğunda ve listedeki her biri için bir grup bileşen oluşturacağınız zaman, uygulamanızda sürünebilecek hata, gelecekte bir zaman gelirse öğelerden birinin listede olmasını beklediğiniz bir değer değilse, değer türünü nasıl ele alacağını bilmiyorsa uygulamanız çökebilir.

İşte bir örnek:

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 (
    <div>
      {Array.isArray(items) && (
        <Header size="tiny" inverted>
          {items.map(({ name, tongueWidth, weight }) => (
            <div style={{ margin: '25px 0' }}>
              <div>Name: {name}</div>
              <div>Width of their tongue: {tongueWidth}cm</div>
              <div>Weight: {weight}lbs</div>
            </div>
          ))}
        </Header>
      )}
      {error && <Header>You received an error. Do you need a linter?</Header>}
    </div>
  )
}

kurbağalar1

Kod gayet iyi çalışacaktı. Şimdi api çağrısına bakarsak ve bunu döndürmek yerine:

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 },
        ],
      },
    }
  },
}

API istemcisinde beklenmeyen bir durum oluştuğunda ve bunun yerine bu diziyi döndürdüğünde veri akışının nasıl işlendiğiyle ilgili bir sorun varsa ne olur?

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 },
        ],
      },
    }
  },
}

Uygulamanız çökecek çünkü bununla nasıl başa çıkacağını bilmiyor:

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

Bunun yerine uygulamanızın çökmesini önlemek için her yinelemede varsayılan bir nesne ayarlayabilirsiniz:

{
  items.map(({ name, tongueWidth, weight } = {}) => (
    <div style={{ margin: '25px 0' }}>
      <div>Name: {name}</div>
      <div>Width of their tongue: {tongueWidth}cm</div>
      <div>Weight: {weight}lbs</div>
    </div>
  ))
}

Ve artık kullanıcılarınız, önlerinde kilitlenen bir sayfa görmediklerinde teknolojiniz ve uzmanlığınız hakkında hüküm vermek zorunda kalmayacaklar:

kurbağalar2

Bununla birlikte, uygulama artık çökmese de, daha ileri gitmenizi ve benzer sorunları olan tüm öğeler için null döndürmek gibi eksik değerleri ele almanızı öneririm, çünkü bunlarda zaten herhangi bir veri yoktur.

7. Uygulayacağınız Şeyi Yeterince Araştırmamak

Geçmişte yaptığım çok önemli bir hata, uyguladığım bir arama girdisine aşırı derecede güvenmek ve oyunda çok erken fikirlerime güvenmekti.

Bununla ne demek istiyorum? Eh, bu arama girişi değil bileşen aşırı güvendiğim şey. Bileşen kolay olmalıydı görev… ve öyleydi.

Arama işlevselliğinin tamamında meydana gelen bir sorunun asıl suçlusu, sorgulara dahil edilen karakterler.

Anahtar kelimeleri bir arama API’sine sorgu olarak gönderirken, bu nedenle klavyede olsalar bile, kullanıcının yazdığı her tuşun geçerli olduğunu düşünmek her zaman yeterli değildir.

Bunun gibi bir normal ifadenin amaçlandığı gibi çalıştığından ve uygulamanızın çökmesine neden olabilecek geçersiz karakterleri dışarıda bırakmaktan kaçındığından %100 emin olun:

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

Bu örnek, bir arama API’si için en güncel, yerleşik normal ifadedir.

İşte daha önce olduğu şey:

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
  }
}

eğik çizgi gördüğünüz gibi / eksik ve bu, uygulamanın çökmesine neden oluyordu! bu karakter kablo üzerinden bir API’ye gönderilirse, API’nin URL’nin ne olacağını düşündüğünü tahmin edin?

Ayrıca internette bulduğunuz örneklere %100 güvenmem. Birçoğu tam olarak test edilmiş çözümler değildir ve düzenli ifadeler söz konusu olduğunda, kullanım durumlarının çoğu için gerçekten bir standart yoktur.

7. Dosya Girişlerinin Boyutlarını Kısıtlamamak

Kullanıcıların seçtiği dosyaların boyutlarını kısıtlamak iyi bir uygulamadır, çünkü çoğu zaman gerçekten inanılmaz derecede büyük bir dosyaya ihtiyacınız yoktur, ancak bir şekilde sıkıştırılabildiğinde, kalitedeki herhangi bir azalma belirtisini kaybetmeden sıkıştırılabilir.

Ancak boyutları belirli bir sınırla sınırlamanın iyi bir uygulama olmasının daha önemli bir nedeni var. Şirketimde, geçmişte kullanıcıların ara sıra “donduğunu” fark ettik süre onların resimleri yükleniyor. Herkesin Alienware 17 R5’i yoktur, bu nedenle kullanıcılarınızın belirli koşullarını göz önünde bulundurmalısınız.

Dosyaları 5 MB (5.000.000 bayt) sınırıyla sınırlamanın bir örneği:

import React, { useState, useEffect } from 'react'

const useUploadStuff = () => {
  const [files, setFiles] = useState([])

  
  const onChange = (e) => {
    const arrFiles = Array.from(e.target.files)
    const filesUnder5mb = arrFiles.filter((file) => {
      const bytesLimit = 5000000
      if (file.size > bytesLimit) {
        
      }
      return file.size < bytesLimit
    })
    setFiles(filesUnder5mb)
  }

  useEffect(() => {
    if (files.length) {
      
    }
  }, [files])

  return {
    files,
    onChange,
  }
}

const UploadStuff = () => {
  const { onChange } = useUploadStuff()

  return (
    <div>
      <h2 style={{ color: '#fff' }}>Hi</h2>
      <div>
        <input
          style={{ color: '#fff' }}
          onChange={onChange}
          type="file"
          placeholder="Upload Stuff"
          multiple
        />
      </div>
    </div>
  )
}

export default UploadStuff

Kullanıcıların belge yüklemeleri gerekirken video oyunları yüklemelerini istemezsiniz!

Çözüm

Ve bu yazının sonu burada bitiyor!

Listemin sadece yarısını bitirdiğim için 2. bölüm olacak (evet!)

Her neyse, okuduğunuz için teşekkür ederim ve gelecekteki güncellemeler için beni takip ettiğinizden emin olun! 4 Temmuz kutlu olsun!

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.