Yêu cầu thg 6 19, 2021 6:49 SA 730 0 2
  • 730 0 2
+1

Tại sao chúng ta không nên cập nhật state trực tiếp?

Chia sẻ
  • 730 0 2

Cho mình hỏi Tại sao chúng ta không nên cập nhật state trực tiếp trong reactjs ạ, mà phải clone nó ra rồi mới update, và có cách nào update mà ko cần clone ra không vì nếu clone ra sẽ lãng phí bộ nhớ không cần thiết?

2 CÂU TRẢ LỜI


Đã trả lời thg 6 19, 2021 9:32 SA
Đã được chấp nhận
+3

Mình trích dẫn example ở trang chủ React: https://reactjs.org/docs/update.html

Lý do khi làm việc với React bạn luôn phải clone array/object trước khi set state là bởi vì nếu bạn ko làm thế thì React sẽ "ko biết" để re-render lại, và bạn sẽ ko thấy cập nhật trên màn hình.

React re-render dựa vào việc so sánh state trước và sau khi thay đổi, nhưng nếu bạn thay đổi trực tiếp state (ví dụ là 1 object), thì ko có cách nào để React có thể check xem là state vừa thay đổi những cái gì, bởi vì state trước đó đã bị override mất rồi. Do đó luôn nhớ clone state trước khi thay đổi nhé bạn, kể cả dùng class component hay hooks

có cách nào update mà ko cần clone ra không vì nếu clone ra sẽ lãng phí bộ nhớ không cần thiết

Trong Javascript khi 1 biến mà ko bị reference đến (ko có ai truy cập đến nó) thì nó sẽ tự được garbage collector của Javascript thu hồi lại để tiết kiệm bộ nhớ nên bạn cũng ko cần quá lo lắng khi clone state vì hầu hết cái state của bạn sẽ chiếm ko đáng kể đến memory. Kể cả bạn có dùng các thư viện để thao tác với immutatable state trong React thì "bên dưới" cái chúng làm cũng là clone state (hoặc tương tự như vậy).


Demo: ví dụ bên dưới mình có 2 state, profiletext, để ý rằng khi update profile mình sửa trực tiếp state của nó:

function App() {
  const [profile, setProfile] = useState({
    name: 'ABC',
    age: 18
  })

  const [text, setText] = useState('Hello World')
  return (
    <div className="App">
      {profile.name} - {profile.age}
      <button onClick={() => {
        profile.name = 'DEF'
        console.log(profile)
      }}>Update Profile</button>

      <h1>{text}</h1>
      <button onClick={() => {
        setText('Hi')
      }}>Update Text</button>
    </div>
  );
}

Khi chạy lên, ta sẽ có 1 số quan sát như sau:

  • bạn sẽ thấy rằng nếu click Update profile thì sẽ ko thấy content thay đổi trên màn hình, vì React ko biết là bạn vừa thay đổi state nên nó sẽ ko re-render.
  • bạn cũng để ý thấy rằng dòng console.log đã in ra giá trị mới nhất của profile (nhưng UI thì ko cập nhật theo)
  • nếu bạn tiếp tục bấm vào Update Text thì thấy rằng profile đã được update trên màn hình, lý do là vì khi click Update Text -> React sẽ re-render lại cả component và nó lấy ra state mới nhất của cả component là profiletext, do đó bạn thấy profile cũng đc update theo mặc dù ta vừa thay đổi chỉ mỗi text.

Sửa lại như sau thì code sẽ chạy đúng ko lỗi lầm gì:

    <button onClick={() => {
        setProfile({
          name: 'DEF',
          age: 21
        })
      }}>Update Profile</button>

// Hoặc
      <button onClick={() => {
        setProfile({
          ...profile,
          name: 'DEF'
        })
      }}>Update Profile</button>

Mình nhớ có lần đọc được bài về 1 vài solution update trực tiếp state mà React vẫn re-render, nhưng rất là chuối và nói chung trong thực tế ko nên đi theo các hướng như vậy. Bạn sẽ thấy kiểu "tự mình bắn vào chân mình" khi dính lỗi hoặc trong tương lai mình đọc lại code 😄. Tốt nhất nên luôn follow pattern của React để tránh lỗi lầm

Chia sẻ
Avatar Thanh Tran @Thanhtran.98
thg 6 20, 2021 8:54 SA

đây nè bác : https://reactjs.org/docs/react-component.html#forceupdate.
forceUpdate, ép component render lại. tuy nhiên nó sẽ render lại toàn component và performace bị giảm. dùng forceUpdate coi như immutable object trong React vô dụng :v

Avatar Mai Trung Đức @maitrungduc1410
thg 6 20, 2021 11:22 SA

@Thanhtran.98 ồ có vẻ chính là đây, cám ơn bạn nhé 😄

Đã trả lời thg 6 20, 2021 8:51 SA
0

react detect một component có được re-render hay không bằng cách check sự thay đổi của props và state. vậy check bằng cách nào? chính là bằng pointer của object props/state.
vậy nên việc clone ra làm thay đổi pointer của state, và khi pointer thay đổi thì react sẽ cho component re-render lại.

Chia sẻ
Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí