Cách làm cho ứng dụng React của bạn hiển thị nhanh hơn

Nov 27 2022
Cung cấp ứng dụng nhanh thì dễ, cung cấp ứng dụng nhanh khó hơn rất nhiều. Dưới đây là một số mẹo để làm cho ứng dụng phản ứng của bạn hiển thị các thành phần của bạn nhanh hơn.

Cung cấp ứng dụng nhanh thì dễ, cung cấp ứng dụng nhanh khó hơn rất nhiều. Dưới đây là một số mẹo để làm cho ứng dụng phản ứng của bạn hiển thị các thành phần của bạn nhanh hơn.

Trong khi chúng tôi cố gắng phân phối các ứng dụng của mình nhanh hơn, chúng tôi thường quên tập trung vào các phương pháp hay nhất. Sau một thời gian, chúng tôi tạo các thành phần phức tạp đến mức khi bạn nhập một vị trí quan trọng không cần hiển thị sẽ được hiển thị. Đây là danh sách những việc nên làm và không nên làm.

Sử dụng React.Memo

Chúng tôi thường không muốn thành phần của mình hiển thị mọi lúc cha mẹ của nó được hiển thị. Chúng ta có thể nói React không hiển thị các thành phần của chúng ta trừ khi nó cần.

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

Không có nhiều hơn 4 đạo cụ cho mỗi thành phần

Có nhiều đạo cụ luôn có vấn đề, mỗi đạo cụ có nghĩa là có thêm một biến để xem xét khi nói đến hiệu suất và nó sẽ khiến mã của bạn khó đọc và khó bảo trì hơn. Thay vì tạo các thành phần có 10 đạo cụ, hãy tạo 3 phần nhỏ hơn với 3–4 đạo cụ.

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

hook khi bạn có các biến sẽ được tính sau khi có gì đó thay đổi. Nó hữu ích vì nếu tính toán của bạn mất thời gian hoặc sau khi tính toán, bạn sẽ nhận được các tham chiếu bộ nhớ khác nhau cho mảng hoặc đối tượng.

Xin đừng quên khi các biến của bạn được thay đổi và bạn chuyển nó cho con, thành phần con sẽ được kết xuất lại.

// 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])

Bạn cần sử dụng hook useCallback khi bạn chuyển chức năng của mình cho một thành phần con. Đừng quên các chức năng sẽ trỏ đến một điểm bộ nhớ khác mỗi khi các thành phần của bạn được hiển thị. Chúng ta cần giữ cuộc gọi lại trước đó trong bộ nhớ để nó không thay đổi mỗi khi chúng ta làm điều gì đó trong thành phần chính và gây ra kết xuất ở phần tử con.

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

Chúng tôi đã quen với việc sử dụng hook này để chuyển nó cho trẻ em và sử dụng các phiên bản của chúng nhưng trường hợp sử dụng này không chỉ có sẵn cho nó. Chúng ta có thể sử dụng nó như một số loại bộ nhớ đệm và cơ chế trạng thái mà không gây ra kết xuất lại.

// 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
  }
}, [])

Đừng bao giờ quên điều này, mỗi khi các thành phần của bạn được hiển thị, các biến bên trong thành phần đó sẽ trỏ đến địa chỉ bộ nhớ khác nhau, khi nói đến các kiểu nguyên thủy như chuỗi và số nguyên, điều này sẽ không gây ra bất kỳ vấn đề nào nhưng nếu bạn đang làm việc với mảng, đối tượng và hàm (vì mỗi chức năng thực sự là các đối tượng đằng sau mui xe). Hãy xem một số ví dụ

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

Bạn có thể nghĩ rằng việc xử lý các biểu mẫu trong phản ứng là dễ dàng, nhưng hãy để tôi đảm bảo với bạn là không. Khi các biểu mẫu của bạn trở nên phức tạp và bạn cần thực hiện một số xác thực, v.v., bạn sẽ gây ra quá nhiều kết xuất. Đó là lý do tại sao việc sử dụng một thư viện tốt là rất quan trọng. Vài năm trước, tôi đã thử nhiều thư viện khác nhau nhưng chỉ có một thư viện đáng được đề cập ở đây; phản ứng-móc-dạng.

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