React uygulamanızın daha hızlı işlenmesini sağlama

Nov 27 2022
Uygulamaları hızlı teslim etmek kolaydır, hızlı uygulamaları teslim etmek ise çok daha zordur. Tepki uygulamanızın bileşenlerinizi daha hızlı hale getirmesi için bazı ipuçlarını burada bulabilirsiniz.

Uygulamaları hızlı teslim etmek kolaydır, hızlı uygulamaları teslim etmek ise çok daha zordur. Tepki uygulamanızın bileşenlerinizi daha hızlı hale getirmesi için bazı ipuçlarını burada bulabilirsiniz.

Uygulamalarımızı daha hızlı sunmaya çalışırken en iyi uygulamalara odaklanmayı genellikle unutuyoruz. Bir süre sonra, o kadar karmaşık bileşenler oluşturuyoruz ki, bir kez bir anahtar yazdığınızda, işlenmeye gerek olmayan yerler işleniyor. İşte yapılması ve yapılmaması gerekenlerin listesi.

React.Memo'yu kullanın

Genellikle, ebeveyni her işlendiğinde bileşenimizin işlenmesini istemeyiz. Gerekmedikçe bileşenlerimizi render etmemesi için React diyebiliriz.

// Wrong usage
// Without React.memo this component will get rendered each time 
// something causes its parent to render
const YourHeavyComponent = (name, title, onClick) => {
    // Render  something really heavy like whole page here
}

export default YourHeavyComponent
// Good usage
// This component will not render unless name, title or onClick changes
const YourHeavyComponent = (name, title, onClick) => {
    // Render  something really heavy like whole page here
}

export default React.memo(YourHeavyComponent)
// This component will not render unless title changes
const YourHeavyComponent = (name, title, onClick) => {
    // Render  something really heavy like whole page here
}

// This usage might better for some stations, use this second argument
// to specify which props  will cause render
export default React.memo(YourHeavyComponent, (prevProps, nextProps) => {
    return prevProps.title === nextProps.title
})

Bileşen başına 4'ten fazla donanıma sahip olmayın

Birçok donanıma sahip olmak her zaman sorunludur, her donanım, performans söz konusu olduğunda dikkate alınması gereken bir değişken daha anlamına gelir ve kodunuzun okunmasını ve bakımını zorlaştırır. 10 destekli bileşenler oluşturmak yerine, 3-4 destekli 3 küçük parça oluşturun.

// this component has too many filters
// it's not a good idea to add filters inside this component
// instead we need to create a seperate component to add filter inputs
// and we can also remove title from here
const List = (title, items, sortBy, keys, filters, onFilterChange, children, pagination) => {
    // Render  something really heavy like whole page here
}
// here userslist wont rendered unless we get a new list
// pagination payload won't cause rendering in filters
const [payload, setPayload] = useState()
const [list, setList] = useState([])
return <>
    <Filters onFilterChange={setPayload} filters={payload.filters} />
    <UserList items={list}/>
    <Pagination onPaginationChange={setPayload} pagination={payload.pagination} />
</>

Bir şey değiştikten sonra hesaplanacak değişkenleriniz olduğunda kanca. Yararlı çünkü hesaplamanız zaman alıyorsa veya hesaplamadan sonra dizi veya nesneler için farklı bellek referansları alacaksınız.

Lütfen unutmayın, değişkenleriniz değiştirildiğinde ve bunu çocuklara ilettiğinizde, children bileşeni yeniden oluşturulacaktır.

// here we use useMemo for purely caching purposes, if we don't use useMemo
// each time this components rendered the calculation will have to re-run 
const heavyCalculated = useMemo(() => doSomeHeavyCalculation(variable1), [variable])
// an example of wrong usage
// each time this components get rendered this
// styles variable will point to different memory address
// and this will cause rerender of YourHeavyComponent
const styles = {
  container:{
    marginLeft: left,
    marginRight: right,
    marginTop: top,
    marginBottom: bottom,
  }
}
// correct usage of useMemo
// this will cache your value and its memory point won't change
// so even if this components gets rendered your YourHeavyComponent won't be rendered again
const styles = useMemo(() => ({
  container:{
    marginLeft: left,
    marginRight: right,
    marginTop: top,
    marginBottom: bottom,
  }
}), [left, right, top, bottom])

İşlevinizi bir alt bileşene geçireceğiniz zaman useCallback kancasını kullanmanız gerekir. Unutmayın, bileşenleriniz her oluşturulduğunda işlevler farklı bir bellek noktasına işaret eder. Ana bileşende her bir şey yaptığımızda değişmemesi ve çocuklarda işlemeye neden olması için önceki geri aramayı bellekte tutmalıyız.

// wrong usage
// each time App components get rendered for some reason
// onClickCallback will be recreated and it will point to different memory address
// so it will cause YourHeavyComponent to re render
const onClickCallback = () => {
  // do some stuff
}

return <div>
  <YourHeavyComponent onClick={onClickCallback} />
</div>

// good usage of onClickCallback
// each time App components if your variable1 don't change
// onClickCallback will point to same memory point 
// so UourHeavyCallback won't render.
const onClickCallback = () => {
  // do some stuff
}

return <div>
  <YourHeavyComponent onClick={onClickCallback} />
</div>

Bu kancayı çocuklara aktarmak ve örneklerini kullanmak için kullanmaya alıştık, ancak bu sadece onun için mevcut olan kullanım durumu değil. Yeniden işlemeye neden olmadan bir tür önbellekleme ve durum mekanizması olarak kullanabiliriz.

// in this example we look for useRef value instead of setting
// sent reference is being used for checking if we send this message before or not
// this could hold in the state but if we put into state it will cause render
// it into state, because we don't want to re-render after we set sent.current
const sent = useRef(false)
const postMessage = useCallback(() => {
  if (!sent.current) {
    // make your api call here
    sent.current = true
  }
}, [])

Bunu asla unutmayın, bileşenleriniz her oluşturulduğunda, o bileşenin içindeki değişkenler farklı bellek adreslerini gösterecek, string ve integer gibi ilkel türler söz konusu olduğunda bu herhangi bir soruna neden olmaz, ancak diziler, nesneler ve işlevlerle çalışıyorsanız (çünkü her işlev aslında kaputun arkasındaki nesnelerdir). Hadi bazı örneklere bakalım

const InlineTest = () => {
    // the usage below will cause YourHeavyComponent to render if
    // something causes InlineTest component to render
    return <YourHeavyComponent style={{
        marginLeft: 10,
        marginRight: 10
    }} />
}
const style = {
    marginLeft: 10,
    marginRight: 10
}

// We move styles outside of component
// this way style will point the same memory address regardless of 
// how many tames InlineTest gets rendered

const InlineTest = () => {
    // the usage below will cause YourHeavyComponent to render if
    // something causes InlineTest component to render
    return <YourHeavyComponent style={style} />
}

const InlineTest = () => {
    // the usage below will cause YourHeavyComponent to render if
    // something causes InlineTest component to render
    // because onClick will be assigned to a new function each time
    return <YourHeavyComponent onClick={() => {
        console.log('clicked');
    }} />;
}
import {useCallback} from "react";

const InlineTest = () => {
    // the usage below is correct way to do it
    // using useCallback will make sure onClick function
    // is the same between renders and it won't cause render in below component
    
    const onClick = useCallback(() => {
        console.log('clicked');
    }, [])
    return <YourHeavyComponent onClick={onClick} />;
}

Formları tepki olarak ele almanın kolay olduğunu düşünebilirsiniz, ancak size garanti etmeme izin verin, öyle değil. Formlarınız karmaşıklaştığında ve bazı doğrulamalar yapmanız gerektiğinde vb. Çok fazla işleme neden olursunuz. Bu yüzden iyi bir kütüphane kullanmak önemlidir. Son birkaç yıldır birçok farklı kütüphane denedim ama burada bahsetmeye değer tek bir kitap var; tepki kancası formu.

import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  const onSubmit = data => console.log(data);


  return (
    /* "handleSubmit" will validate your inputs before invoking "onSubmit" */
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* register your input into the hook by invoking the "register" function */}
      <input defaultValue="test" {...register("example")} />
      
      {/* include validation with required or other standard HTML validation rules */}
      <input {...register("exampleRequired", { required: true })} />
      {/* errors will return when field validation fails  */}
      {errors.exampleRequired && <span>This field is required</span>}
      
      <input type="submit" />
    </form>
  );
}