Những điều tệ hại bạn làm trong Redux - dispatch trong các phương thức lifecycle

Cập nhật ngày: 19/04/2024 - Đã có 2075 lượt xem bài viết này!
Những điều tệ hại bạn làm trong Redux - dispatch trong các phương thức lifecycle
Chúng tôi đã làm những điều tệ hại khi đang phát triển 1 dự án, những điều mà đáng ra không nên xảy đến. Thứ tồi tệ đó chính là việc chúng tôi đã dispatch các lời gọi trong các những lifecycle method của React như componentWillReceiveProps, componentWillUpdate, và componentDidUpdate.

Những điều tệ hại bạn làm trong Redux - dispatch trong các phương thức lifecycle

Đây là 1 trường hợp cụ thể. Chúng tôi có 2 component khác nhau, truy cập vào 2 state khác nhau:

class Address extends React.Component {
  render() {
    return ;
  }
}
function mapStateToProps(state) {
  return {
    address: state.address
  }
}
function mapDispatchToProps(dispatch) {
  return {
    changeAddress: (address) => dispatch(changeAddress(address)),
  }
}
connect(mapStateToProps, mapDispatchToProps)(Address);

 

class Zipcode extends React.Component {
  render() {
    return ;
  }
}
function mapStateToProps(state) {
  return {
    zipcode: state.zipcode
  }
}
function mapDispatchToProps(dispatch) {
  return {
    changeZipcode: (zipcode) => dispatch(changeZipcode(zipcode)),
  }
}
connect(mapStateToProps, mapDispatchToProps)(Zipcode);

Bây giờ giả sử tôi muốn thêm 1 thông báo cho component Address khi người dùng nhập vào địa chỉ không xuất hiện trong zip code mà người dùng cung cấp.Ta sẽ lưu trữ dữ liệu của thông báo này trong state redux. Có rất nhiều cách để làm điều này, tuy nhiên tối thiểu thì cách mà ta nên đưa ra phải kiểm tra địa chỉ khi 1) địa chỉ thay đổi và 2) zip code thay đổi.

Ứng dụng của chúng tôi sử dụng redux-saga. Giả sử rằng ta cần thực thi 1 số lời gọi network để làm công việc kiểm tra. Do đó ta sẽ sử dụng 1 số async middleware.

Giải pháp thứ nhất

Ta dispatch 1 action khi  changeZipcode hoặc changeAddress được gọi đến. Ví dụ, hàm mapDispatchToProps của component Zipcode sẽ thay đổi thành:

function mapDispatchToProps(dispatch) {
  return {
    changeZipcode: (zipcode) => {
      dispatch(changeZipcode(zipcode));
      dispatch(checkAddress());
    }
  }
}

Sau đo chúng tôi có saga chờ action checkAddress để làm công việc kiểm tra địa chỉ dựa trên zipcode và cập nhật vài state, trả về và render lại Address component.

Tôi thực sự không thích giải pháp này chút nào do do cả changeZipcode lẫn changeAddress đều sẽ phải sử dụng cùng 1 logic.

Tham khảo các khóa học lập trình online, onlab, và thực tập lập trình tại iMicroSoft Việt Nam

Giải pháp thứ 2

Có thể sử dụng luôn saga để chờ các action từ changeZipcode hoặc changeAddress và để nó làm công việc kiểm tra khi vấn đề xảy ra. Bây giờ thì chúng tôi không cần action checkAddress.

Giải pháp không nên sử dụng!

Không may là chính chúng tôi đã sử dụng cách này. Các bạn có thể nhận thấy là zipcode cuối cùng vẫn sẽ không thay đổi. Thay vào đó chúng tôi thêm phương thức lifecycle componentWillReceiveProps trong componen Address để kiểm tra khi nào thì địa chỉ hoặc zipcode thay đổi. Nếu có thay đổi xảy ra, dispatch 1 action để kiểm tra địa chỉ.

class Address extends React.Component {
  componentWillReceiveProps(nextProps) {
    if (this.props.zipcode !== nextProps.zipCode || this.props.address !== nextProps.address) {
      this.props.checkAddress();
    }
  }
  render() {
    return (
      

{this.props.addressAlert}

;
); } } function mapStateToProps(state) { return { address: state.address, addressAlert: state.addressAlert, zipcode: state.zipcode, } } function mapDispatchToProps(dispatch) { return { changeAddress: (address) => dispatch(changeAddress(address)), checkAddress: () => dispatch(checkAddress()), } } connect(mapStateToProps, mapDispatchToProps)(Address);

Khi lần đầu thấy đoạn code này tôi đã hơi lạnh lưng. Tôi cuộn chuột lên xuống và tự hỏi Tại sao nhiều lần. Có gì đó sai sai đã xảy ra. Tại sao Address lại cần quan tâm đến zipcoe? Tại sao?

Có thể bạn sẽ cho rằng phương án này đâu có tệ. Thậm chí còn khá tốt nữa đằng khác. Address liên quan đên zipcode bởi vì nó cần cập nhật 1 thông báo về địa chỉ khi zipcode thay đổi. Tuy nhiên vấn đề là như thế này: component không nên quan tâm (hay biết) đến các thay đổi của state bên ngoài nó. Vấn đề này trở nên rõ ràng nhất khi bạn áp dụng redux vào project của bạn.

Các vấn đề tiềm ẩn

Tôi sẽ trình bày thêm 1 số vấn đề nảy sinh của phương án trên. Giả sử bạn sẽ lấy về 1 state khi có sự thay đổi trong ứng dụng, kéo theo các thành phần khác trong ứng dụng thay đổi theo. Lúc này bạn sẽ cần thêm state đó vào bất cứ component nào cần state đó, hay nói cách khác, bạn sẽ phải viết componentWillReceiveProps để kiểm tra trong từng component đó. Vậy lúc này bạn sẽ làm cách nào để đảm bảo 2 component khác nhau không dispatch cùng 1 action khi mà state chúng nhận được thay đổi?

Hoặc tệ hơn, bạn sẽ gặp phải tình trạng sau:

-  Đầu tiên component A dispatch 1 action.

-  Component B lắng nghe sự thay đổi state - kết quả mà component A dispatch, sau đó thực hiện dispatch lần 2.

-  Component C lắng nghe sự thay đổi state - kết quả mà component B dispatch, sau đó thực hiện dispatch lần 3.

-  Và mọi việc vẫn sẽ tiếp tục...

Ứng dụng của bạn sẽ phải trải qua nhiều bước, điều này dẫn đến việc sẽ rất khó để truy ngược xem action nào là action đầu tiên khởi động chuỗi biến đổi này.

Một điều cuối cùng mà tôi muốn nói: việc dùng các phương thức lifecycle theo cách này không hẳn là 1 điều tệ. Chắc chắn bạn sẽ dùng đến chúng 1 khi component của bạn cần có state của riêng nó. Hoặc là bạn cần truy cập thẳng vào DOM do đang làm việc với 1 thư viện không chính chủ React. Tuy nhiên, chúng không bao giờ nên được sử dụng khi mà chúng có thể tạo ra những action làm thay đổi state trong redux, khi phản hồi từ các sự kiện redux.

Kết luận: hãy viết component đơn giản nhất có thể, tốt nhất thì nó phải là 1 hàm của props.

BTV. Phạm Thị Mỹ Phương
Phòng Truyền Thông ImicroSoft Hồ Chí Minh
Hotline: 0916 878 224
Email: phuongptm@imicrosoft.edu.vn

Bạn đang muốn tìm kiếm 1 công việc với mức thu nhập cao.
✅ Hoặc là bạn đang muốn chuyển đổi công việc mà chưa biết theo học ngành nghề gì cho tốt.
✅ Giới thiệu với bạn Chương trình đào tạo nhân sự dài hạn trong 12 tháng với những điều đặc biệt mà chỉ có tại IMIC và đây cũng chính là sự lựa chọn phù hợp nhất dành cho bạn:
👉 Thứ nhất: Học viên được đào tạo bài bản kỹ năng, kiến thức chuyên môn lý thuyết, thực hành, thực chiến nhiều dự án và chia sẻ những kinh nghiệm thực tế từ Chuyên gia có nhiều năm kinh nghiệm dự án cũng như tâm huyết truyền nghề.
👉 Thứ hai: Được ký hợp đồng cam kết chất lượng đào tạo cũng như mức lương sau tốt nghiệp và đi làm tại các đối tác tuyển dụng của IMIC. Trả lại học phí nếu không đúng những gì đã ký kết.
👉 Thứ ba: Cam kết hỗ trợ giới thiệu công việc sang đối tác tuyển dụng trong vòng 10 năm liên tục.
👉 Thứ tư: Được hỗ trợ tài chính với mức lãi suất 0 đồng qua ngân hàng VIB Bank.
👉  Có 4 Chương trình đào tạo nhân sự dài hạn dành cho bạn lựa chọn theo học. Gồm có:
1)  Data Scientist full-stack
2)  Embedded System & IoT development full-stack
3)  Game development full-stack
4)  Web development full-stack 
✅ Cảm ơn bạn đã dành thời gian lắng nghe những chia sẻ của mình. Và tuyệt vời hơn nữa nếu IMIC được góp phần vào sự thành công của bạn. 
✅ Hãy liên hệ ngay với Phòng tư vấn tuyển sinh để được hỗ trợ về thủ tục nhập học.
✅ Chúc bạn luôn có nhiều sức khỏe và thành công!

Tham khảo các khóa đào tạo nhân sự qua danh mục