Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lưu ý khi viết custom hook cho Redux (Split state and actions) #65

Open
NguyenAnhTuan1912 opened this issue May 3, 2023 · 0 comments
Assignees
Labels
documentation Improvements or additions to documentation

Comments

@NguyenAnhTuan1912
Copy link
Collaborator

Note

Cách redux hoạt động thì tụi mình đều biết cả rồi, khi update state, thì component (function) nào subscribe thông qua useSelector() thì nó sẽ được chạy lại (re-render, re-execute). Cho nên, khi viết hook thì nên chú ý tới một điều này nữa. Giả sử bây giờ có trường hợp như này đi.

Problems

Có một hook như sau

function useData() {
  let data = useSelector(state => state.data)
  let dispatch = useDispatch()

  let updateData = data => dispatch(updateDataState(data))

  return {
    data,
    updateData
  }
}

Component A và Component B, đều sử dụng redux để cập nhật dữ liệu thông qua useData. Cho nên khi A update state thì B sẽ render lại và bởi vì A và B đều subscribe vào state của redux, cho nên cả thằng A cũng sẽ render lại luôn. Ok, mọi thứ ổn nếu như component A cũng dùng state. Tuy nhiên nếu như A không dùng state thì sao?
image
(1): A và B đều subscribe data state.
(2): A sẽ update data thông qua updateData(newData).
(3): Reducer sẽ xử lý state, cập nhật state mới.
(4): Update lại state, component A và B sẽ được render lại.

Tiếp tục giả sử một trường hợp khác đi, trường hợp thực tế, khi Explore load được 5 dữ liệu của places, thì t sẽ dùng redux để lưu lại thông tin của place đó để có thể load trước khi vào place details và chờ các dữ liệu khác được trả về. Thì lúc này, các HorizontalPlaceCard sẽ bị render lại, bởi vì t đã subscribe state của redux trong mỗi component đó. Nếu như có 100 cái HorizontalPlaceCard thì sao? Rất tiếc cho cái vấn đề này là t đã có giải pháp.

Solutions

Trong mỗi Redux sẽ có 2 phần chính đó là state và action. State sẽ là thằng luôn được cập nhật khi được thay đổi và thằng action thì không, nó là các hàm tĩnh, không thay đổi theo thời gian. Vì action được thiết kế theo hướng dấu state, cho nên sẽ khá dễ để tách phần state và action ra làm hai. Từ useData thành useDataStateuseDataActions. Lúc này thì chỉ có thằng nào dùng useDataState thì mới subscribe vào state của Redux, có nghĩa là chỉ có thằng đó mới render lại thôi.
useDataState

function useDataState() {
  return = useSelector(state => state.data);
}

useDataActions

function useDataAction() {
  let dispatch = useDispatch()

  let updateData = data => dispatch(updateDataState(data))

  return {
    updateData
  }
}

Và giờ A chỉ dùng useDataActions để update state và B dùng useDataState để dùng data state. Nên lúc này, chỉ có B render lại thôi, A vẫn thế.
image
(1): A dùng useDataActions, B dùng useDataState (subscribe vào redux state).
(2): A sẽ update data thông qua updateData(newData).
(3): Reducer sẽ xử lý state, cập nhật state mới.
(4): Update lại state, chỉ có component B sẽ được render lại. A sẽ vẫn thế.

Giờ thì ví dụ thực luôn nè. Ở đây t có 3 hook usePlaceDetailsActions, usePlaceDetailsStateusePlaceDetails để test.
usePlaceDetailsActions

export function usePlaceDetailsActions() {
  let dispatch = useDispatch();

  let updatePlaceDetails = placeDetails => dispatch(updateCurrentPlaceDetailsState(placeDetails));

  return {
    updatePlaceDetails
  }
}

usePlaceDetailsState

export function usePlaceDetailsState() {
  return useSelector(placeDetailsSelector);
}

usePlaceDetails

export function usePlaceDetails() {
  let data = useSelector(placeDetailsSelector);
  let dispatch = useDispatch();

  let updatePlaceDetails = placeDetails => dispatch(updateCurrentPlaceDetailsState(placeDetails));

  return {
    data,
    updatePlaceDetails
  }
}

Đầu tiên là dùng usePlaceDetails, và log trong HorizontalPlaceCard
image

Tiếp trong PlaceDetailScreen dùng tiếp hook usePlaceDetails hoặc usePlaceDetailsState cũng được, và log thêm ở đây nữa.
image

Giờ thì xem logs
image
Thấy không, HorizontalPlaceDetails sẽ render lại.

Giờ thì tách riêng ra, HorizontalPlaceCard dùng usePlaceDetailsActions, còn PlaceDetailScreen dùng usePlaceDetailsState
Trong HorizontalPlaceCard
image

Trong PlaceDetailScreen
image

Giờ thì xem logs
image

Giờ thì HorizontalPlaceCard không re-rendẻ lại nữa. Ok thì cái này tới đây thôi. Ae lưu ý nhá.

@NguyenAnhTuan1912 NguyenAnhTuan1912 added the documentation Improvements or additions to documentation label May 3, 2023
@NguyenAnhTuan1912 NguyenAnhTuan1912 self-assigned this May 3, 2023
@NguyenAnhTuan1912 NguyenAnhTuan1912 changed the title Lưu ý khi viết custom hook cho Redux Lưu ý khi viết custom hook cho Redux (Split state and actions) May 3, 2023
@NguyenAnhTuan1912 NguyenAnhTuan1912 pinned this issue May 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

1 participant