Sử dụng Redux với React Hook trong React Native

Với việc React Hook đã được sử dụng rộng rãi, khả năng xử lý state và side effect của Component đã quá thông dụng trong function component. React Redux đã đưa ra những hàm Hook API như là sự thay thế cho connect().

Trong bài hướng dẫn này, chúng ta sẽ xây dựng một app React Native đơn giản để cho người dùng viết note và lưu chúng lại. Nếu như các bạn đã quen với hàm React Hook cơ bản và cách sử dụng chúng thì bạn có thể tiếp tục với bài hướng dẫn này, nếu không các bạn nên tìm hiểu trước về các mục cơ bản của React Hook trước.

Cài đặt Redux

Bạn hãy cài đặt Redux qua hướng dẫn ở đây : https://redux.js.org/introduction/installation/ Sau đó hãy kiểm tra lại dependencies trong file package.json.

"dependencies": {
 "@react-native-community/masked-view": "0.1.5",
 "expo": "~36.0.0",
 "react": "~16.9.0",
 "react-dom": "~16.9.0",
 "react-native": "https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz",
 "react-native-gesture-handler": "~1.5.0",
 "react-native-paper": "3.4.0",
 "react-native-reanimated": "~1.4.0",
 "react-native-safe-area-context": "0.6.0",
 "react-native-screens": "2.0.0-alpha.12",
 "react-navigation": "4.0.10",
 "react-navigation-stack": "2.0.10",
 "react-redux": "7.1.3",
 "redux": "4.0.5"
 },

Sau đó hãy cài đặt dependencies sau bằng terminal

yarn add redux react-redux lodash.remove

Cài đặt trên giúp cho bạn quản lý tất cả các file liên quan đến Redux vào cùng một nơi rất tiện lợi, nó gọi là ducks. Bạn có thể tham khảo bài viết sau để tìm hiểu rõ hơn: https://medium.com/swlh/the-good-the-bad-of-react-redux-and-why-ducks-might-be-the-solution-1567d5bdc698

Thêm action type và creator

Khi Redux kiểm soát state của cả ứng dụng, state được diễn đạt như là một Javascript object. Hãy hiểu rằng object này là read-only, chúng ta không thể tự thay đổi được nó. Mà phải dùng action để làm.

Action là các event trong redux. Nó có thể là việc bấm nút, timer hoặc network request.

Để bắt đầu, hãy tạo thư mục redux trong src. Sau đó tạo file noteApp.js.

Vì ứng dụng này làm công việc liên quan đến note, trong file vừa mới tạo, hãy bắt đầu với 2 action như sau.


// Action Types

export const ADD_NOTE = 'ADD_NOTE'
export const DELETE_NOTE = 'DELETE_NOTE'

Kế tiếp là các hàm tạo các action này.

// Action Creators

let noteID = 0

export function addnote(note) {
  return {
    type: ADD_NOTE,
    id: noteID++,
    note
  }
}

export function deletenote(id) {
  return {
    type: DELETE_NOTE,
    payload: id
  }
}

Thêm Reducer

Phần nhận những Action được gọi là reducer. Bất cứ khi nào action được kích hoạt, state của ứng dụng sẽ thay đổi. Việc quản lý state này dựa vào reducer.

Reducer là một pure function tính toán state tiếp theo dựa vào state trước nó. Nó luôn trả về cùng một output nếu state không thay đổi. Nó có 2 tham số stateaction và phải luôn trả về state.

State khởi tạo sẽ là một array trống. Bạn hãy import thêm remove trong lodash.remove mà bạn đã thêm trước đó.

// import the dependency
import remove from 'lodash.remove'

// reducer

const initialState = []

function notesReducer(state = initialState, action) {
  switch (action.type) {
    case ADD_NOTE:
      return [
        ...state,
        {
          id: action.id,
          note: action.note
        }
      ]

    case DELETE_NOTE:
      const deletedNewArray = remove(state, obj => {
        return obj.id != action.payload
      })
      return deletedNewArray

    default:
      return state
  }
}

export default notesReducer

Tùy chỉnh Redux store

Store là một object kết nối các action với reducer. Nó cung cấp và giữ các state ở cấp độ ứng dụng thay vì trong các component.

Với việc Reducer được tạo xong, tạo file mới store.js bên trong src/redux/. Thêm function createStore trong redux.

import { createStore } from 'redux'
import notesReducer from './notesApp'

const store = createStore(notesReducer)

export default store

Để kết nối Redux store với React native app hãy làm như sau trong file App.js

import React from 'react'
import { Provider as PaperProvider } from 'react-native-paper'
import AppNavigator from './src/navigation'
import { Provider as StoreProvider } from 'react-redux'
import store from './src/redux/store'

// modify the App component
export default function App() {
  return (
    <StoreProvider store={store}>
      <PaperProvider>
        <AppNavigator />
      </PaperProvider>
    </StoreProvider>
  )
}

Truy cập vào global state

Để truy cập, hãy dùng hàm useSelector của Hook. Nó sẽ giống với mapStateToProps ở trong connect(). Điểm khác biệt giữa chúng là hàm hook có thể trả về nhiều thứ không chỉ có object.

Mở file ViewNotes.js. Hãy thêm như sau

// ...after rest of the imports
import { useSelector } from 'react-redux'

Tiếp theo, thay vì lưu note vào trong một notes array bằng cách dùng useState(), hãy thay nó như sau

const notes = useSelector(state => state)

Dispatch action

Hàm useDispatch() hoàn toàn giống với hàm dispatch ở trong Redux store. Thêm nó như sau

import { useSelector, useDispatch } from 'react-redux'

Để dispatch action, làm như sau

const dispatch = useDispatch()
// Note action
const addNote = note => dispatch(addnote(note))
const deleteNote = id => dispatch(deletenote(id))

Và thêm các action này vào UI để trigger

<List.Item
  title={item.note.noteTitle}
  description={item.note.noteValue}
  descriptionNumberOfLines={1}
  titleStyle={styles.listTitle}
  onPress={() => deleteNote(item.id)}
/>

Kết thúc

Với việc sử dụng useSelectoruseDispatch, chúng ta không chỉ loại được phần nhiều code, mà còn đưa ra một cách truy cập hay hơn cho functional component. Các bạn nên sử dụng cách này với Redux sẽ giảm được khá nhiều thời gian code đó . Cảm ơn các bạn đã đón đọc.

REF: https://heartbeat.fritz.ai/using-redux-with-react-hooks-in-a-react-native-app-cc410a77f3e2