UseCallback / useMemo làm gì trong React? (ok)

https://www.it-swarm-vi.tech/vi/javascript/usecallback-usememo-lam-gi-trong-react/808445097/

src\Counter.jsx

import { useCallback, useEffect, useMemo, useState } from "react";
function Counter() {
  const [count, setCount] = useState(0);
  const [wordIndex, setWordIndex] = useState(0);
  const words = ['hey', 'this', 'is', 'cool'];
  const word = words[wordIndex];
  const computeLetterCount = word => {
    let i = 0;
    while (i < 1000) i++;
    return word.length;
  };
  const letterCount = useMemo(() => computeLetterCount(word), [word]);
  return (
    <div style={{ padding: '15px' }}>
      <h2>Increment a counter (fast ⚡️)</h2>
      <p>Counter: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <br />
      <h2>Compute number of letters (slow 🐌)</h2>
      <p>
        "{word}" has {letterCount} letters
      </p>
      <button
        onClick={() => {
          const next = wordIndex + 1 === words.length ? 0 : wordIndex + 1;
          setWordIndex(next);
        }}
      >
        Next word
      </button>
    </div>
  )
}
export default Counter;

src\index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
reportWebVitals();

UseCallback / useMemo làm gì trong React?

Như đã nói trong docs , useCallback Trả về một cuộc gọi lại được ghi nhớ.

Vượt qua một cuộc gọi lại nội tuyến và một loạt các đầu vào. useCallback sẽ trả về một phiên bản ghi nhớ của cuộc gọi lại chỉ thay đổi nếu một trong những đầu vào đã thay đổi. Điều này hữu ích khi chuyển các cuộc gọi lại đến các thành phần con được tối ưu hóa dựa trên sự bình đẳng tham chiếu để ngăn chặn các kết xuất không cần thiết (ví dụ: ShouldComponentUpdate).

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

Nhưng làm thế nào để nó hoạt động và nơi nào là tốt nhất để sử dụng nó trong React?

P.S. Tôi nghĩ rằng trực quan hóa với ví dụ codepen sẽ giúp mọi người hiểu rõ hơn về nó. Giải thích trong tài liệ .javascriptreactjsreact-hooks 395 thg 11, 2018RTW

Điều này được sử dụng tốt nhất khi bạn muốn ngăn chặn kết xuất lại không cần thiết để có hiệu suất tốt hơn.

So sánh hai cách chuyển cuộc gọi lại này với các thành phần con được lấy từ React Docs :

1. Chức năng mũi tên trong kết xuất

class Foo extends Component {
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <Button onClick={() => this.handleClick()}>Click Me</Button>;
  }
}

2. Ràng buộc trong Trình xây dựng (ES2015)

class Foo extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <Button onClick={this.handleClick}>Click Me</Button>;
  }
}

Giả sử <Button> được triển khai dưới dạng PureComponent, cách đầu tiên sẽ khiến <Button> hiển thị lại mỗi lần <Foo> tái hiện lại bởi vì một chức năng mới được tạo trong mỗi cuộc gọi render() . Theo cách thứ hai, phương thức handleClick chỉ được tạo một lần trong hàm tạo của <Foo> và được sử dụng lại qua các kết xuất.

Nếu chúng ta dịch cả hai cách tiếp cận thành phần chức năng bằng cách sử dụng hook, thì đây là các cách tương đương (sắp xếp):

1. Chức năng mũi tên trong kết xuất -> gọi lại không ghi nhớ

function Foo() {
  const handleClick = () => {
    console.log('Click happened');
  }
  return <Button onClick={handleClick}>Click Me</Button>;
}

2. Ràng buộc trong Trình xây dựng (ES2015) -> Cuộc gọi lại được ghi nhớ

function Foo() {
  const memoizedHandleClick = useCallback(
    () => console.log('Click happened'), [],
  ); // Tells React to memoize regardless of arguments.
  return <Button onClick={memoizedHandleClick}>Click Me</Button>;
}

Cách thứ nhất tạo ra cuộc gọi lại trên mỗi cuộc gọi của thành phần chức năng nhưng theo cách thứ hai, React ghi nhớ chức năng gọi lại cho bạn và cuộc gọi lại không được tạo nhiều lần.

Trong hầu hết các trường hợp, làm theo cách đầu tiên là tốt. Là trạng thái React docs:

Có thể sử dụng các hàm mũi tên trong phương thức kết xuất không? Nói chung, vâng, nó ổn, và nó thường là cách dễ nhất để truyền tham số cho các hàm gọi lại.

Nếu bạn có vấn đề về hiệu suất, bằng mọi cách, hãy tối ưu hóa!

806 thg 11, 2018Yangshun Tay

Tôi đã làm một ví dụ nhỏ để giúp người khác hiểu rõ hơn về cách hành xử của nó. Bạn có thể chạy bản demo tại đây hoặc đọc mã dưới đây:

import React, { useState, useCallback, useMemo } from 'react';
import { render } from 'react-dom';

const App = () => {
    const [state, changeState] = useState({});
    const memoizedValue = useMemo(() => Math.random(), []);
    const memoizedCallback = useCallback(() => console.log(memoizedValue), []);
    const unMemoizedCallback = () => console.log(memoizedValue);
    const {prevMemoizedCallback, prevUnMemoizedCallback} = state;
    return (
      <>
        <p>Memoized value: {memoizedValue}</p>
        <p>New update {Math.random()}</p>
        <p>is prevMemoizedCallback === to memoizedCallback: { String(prevMemoizedCallback === memoizedCallback)}</p>
        <p>is prevUnMemoizedCallback === to unMemoizedCallback: { String(prevUnMemoizedCallback === unMemoizedCallback) }</p>
        <p><button onClick={memoizedCallback}>memoizedCallback</button></p>
        <p><button onClick={unMemoizedCallback}>unMemoizedCallback</button></p>
        <p><button onClick={() => changeState({ prevMemoizedCallback: memoizedCallback, prevUnMemoizedCallback: unMemoizedCallback })}>update State</button></p>
      </>
    );
};

render(<App />, document.getElementById('root'));

Last updated

Was this helpful?