Redux vs Angular 2



  • Xin chào các bạn, bữa hôm có vụ nghiên cứu về tốc độ của mấy framework, ngồi so sánh thử tốc độ của react, angular 1, 2 như nào?
    Cái nào ngon hơn, nên dùng cái nào mà không nên dùng cái nào?
    Test thử vài cái thấy angular 2 chạy nhanh thậc, nhưng không biết khi kết hợp với redux trong dự án thì kết quả nó sẽ cho ra như thế nào.
    Bài viết hôm nay mình sẽ nói sơ qua về cách kết hợp giữa Redux và Angular 2.

    Để hiểu rõ chúng ta cùng xem ví dụ như sau:
    Các thành phần chính:

    • ChatNavBar: chứa số lượng tin nhắn chưa đọc
    • ChatThreads: hiển thị danh sách đối tượng mà mình sẽ tạo hội thoại
    • ChatWindow: hiển thị danh sách tin nhắn của cuộc hội thoại hiện tại

    Models

    Chúng ta sẽ cần 3 đối tượng chính:

    • User: thông tin người tham gia hội thoại
    • Message: nội dung tin nhắn
    • Thread: lưu trữ tập nội dung tin nhắn của cuộc hội thoại

    Reducers

    Chúng ta sẽ sử dụng 2 reducers:

    • UserReducer: xử lý thông tin về user hiện tại
    • ThreadsReducer: xử lý tập các threads và messages của hội thoại

    Implementing

    Chúng ta sẽ lần lượt đi vào định nghĩa từng models

    Models

    User.ts

    export interface User {
      id: string;
      name: string;
      avatarSrc: string;
      isClient?: boolean;
    }
    

    Biến isClient sẽ cho chúng ta biết người dùng có phải là người dùng đang sử dụng app hay không?

    Thread.ts

    export interface Thread {
      id: string;
      name: string;
      avatarSrc: string;
      messages: Message[];
    }
    

    Message.ts

    export interface Message {
      id?: string;
      sentAt?: Date;
      isRead?: boolean;
      thread?: Thread;
      author: User;
      text: string;
    }
    

    Với mỗi message chúng ta sẽ có:

    • id: id của message
    • sentAt: thời gian send message
    • isRead: biến boolean kiểm tra trang thái tin nhắn đã được đọc hay chưa
    • author: user send message
    • thread: tham chiếu tới Thread đang quản lý

    App State

    Chúng ta đã có đầy đủ model cần thiết, tuy nhiên chúng ta cũng cần 1 biến để lưu trữ trạng thái của app, nó sẽ cần cả users, và tập các thread:

    export interface AppState {
        users: UsersState;
        threads: ThreadsState;
    }
    

    The Root Reducer

    Chúng ta cùng xem root reducer dưới đây:

    export interface AppState {
        users: UsersState;
        threads: ThreadsState;
    }
    const rootReducer: Reducer<AppState> = combineReducers<AppState>({
        users: UsersReducer,
        threads: ThreadsReducer
    });
    

    Có một vài điểm đáng chú ý ở đây:

    • UsersReduces sẽ hoạt động theo users với type là UsersState
    • ThreadsReducer sẽ hoạt động theo threads với type là ThreadsState

    UsersState

    • UsersState sẽ tham chiếu tới currentUser.
      UserReducer.ts:
    export interface UsersState {
    currentUser: User;
    };
    const initialState: UsersState = {
    currentUser: null
    };
    

    ThreadsReducer.ts

    export interface ThreadsEntities {
    [id: string]: Thread;
    }
    export interface ThreadsState {
    ids: string[];
    entities: ThreadsEntities;
    currentThreadId?: string;
    };
    const initialState: ThreadsState = {
    ids: [],
    currentThreadId: null,
    entities: {}
    };
    

    Chúng ta sẽ định nghĩa 1 interface là ThreadsEntities nó sẽ map với các thread ids của list Threads, với ý tưởng đưa ra là việc tìm kiếm các thread sẽ dễ dàng hơn
    Chúng ta cũng sẽ lưu thêm 1 biến là curentThreadId - thread hiện tại mà user đang trỏ vào

    Building the Reducers (and Action Creators)

    Về cá nhân mình thấy thì quản lý action là mục mình hứng thú nhất :D
    Chúng ta sẽ đi vào các action chính

    Set Current User Action Creators

    UsersState sẽ lưu thông tin current_user, chúng ta sẽ cần thêm các actions như sau:
    actions/UserActions.ts

    export const SET_CURRENT_USER = '[User] Set Current';
        export interface SetCurrentUserAction extends Action {
        user: User;
    }
    export const setCurrentUser: ActionCreator<SetCurrentUserAction> =
        (user) => ({
            type: SET_CURRENT_USER,
            user: user
        });
    

    Chúng ta định nghĩa một constant SetCurrentUserAction, chúng ta sẽ sử dụng để chuyển đổi trong reducer
    Ngoài ra cũng định nghĩa themem subinterface SetCurrentUserAction được kế thừa từ action và thêm vào thuộc tính user

    UsersReducer - Set Current User

    Chúng ta cùng chú ý vào UsersReducer:

    export const UsersReducer =
        function(state: UsersState = initialState, action: Action): UsersState {
            switch (action.type) {
            case UserActions.SET_CURRENT_USER:
                const user: User = (<UserActions.SetCurrentUserAction>action).user;
                return {
                    currentUser: user
                };
                default:
                    return state;
            }
    };
    

    UsersReducer sẽ lấy 1 UsersState làm đối số đầu tiên (lưu ý là nó cũng không phải là AppState mà chỉ là 1 reducer con trên, 1 nhánh trên cây state)
    UsersReducer cung giống với reducers, sẽ trả về một state mới, trong trường hợp này sẽ trả về theo UsersState.
    Để set current user chúng ta cần nhận 1 user từ 1 action gửi đến. chúng ta sẽ hứng action UserActions.SetCurrentUserAction và sau đó đọc thuộc tính user

    Thread and Mesages

    Nội dung chính của ứng dụng là việc gửi và nhận tin. Ở mục này chúng ta sẽ có 3 action chính cần support:

    • thêm mới thread vào state
    • thêm message vào 1 thread
    • chọn thread
      Sau đây chúng ta cùng đi đến với việc tạo mới 1 thread

    thêm mới thread trong action creators

    Chúng ta cùng đến với actions/ThreadActions.ts như bên dưới

     export const ADD_THREAD = '[Thread] Add';
     export interface AddThreadAction extends Action {
         thread: Thread;
     }
     export const addThread: ActionCreator<AddThreadAction> =
         (thread) => ({
             type: ADD_THREAD,
             thread: thread
         })
    

    Tượng tự như UserAction, ThreadAction sẽ định nghĩa một const ADD_THREAD để chuyển đổi action.

    Thêm mới thread tron reducer

    tiếp đến với file reducers/ThreadsReducer.ts

    export const ThreadsReducer =
         function(state: ThreadsState = initialState, action: Action): ThreadsState {
                 switch (action.type) {
    
                // Adds a new Thread to the list of entities
                 case ThreadActions.ADD_THREAD: {
                        const thread = (<ThreadActions.AddThreadAction>action).thread;
    
                         if (state.ids.includes(thread.id)) {
                             return state;
                         }
    
                         return {
                         ids: [ ...state.ids, thread.id ],
                         currentThreadId: state.currentThreadId,
                             entities: Object.assign({}, state.entities, {
                                 [thread.id]: thread
                                 })
                             };
                         }
    

    thêm mới message trong action creators

    actions/ThreadActions.ts

     export const ADD_MESSAGE = '[Thread] Add Message';
     
     export interface AddMessageAction extends Action {
         thread: Thread;
         message: Message;
     }
     
     export const ADD_MESSAGE = '[Thread] Add Message';
    export interface AddMessageAction extends Action {
    	thread: Thread;
    	message: Message;
    }
    

    Thêm mới message trong reducer

     case ThreadActions.ADD_MESSAGE: {
         const thread = (<ThreadActions.AddMessageAction>action).thread;
         const message = (<ThreadActions.AddMessageAction>action).message;
    
         // special case: if the message being added is in the current thread, then
         // mark it as read
         const isRead = message.thread.id === state.currentThreadId ?
         true : message.isRead;
         const newMessage = Object.assign({}, message, { isRead: isRead });
    
         // grab the old thraed from entities
         const oldThread = state.entities[thread.id];
    
         // create a new thread which has our newMessage
         const newThread = Object.assign({}, oldThread, {
             messages: [...oldThread.messages, newMessage]
         });
    
         return {
             ids: state.ids, // unchanged
            currentThreadId: state.currentThreadId, // unchanged
            entities: Object.assign({}, state.entities, {
                 [thread.id]: newThread
             })
         };
     
    

    chọn current thread trong action creator

     export const SELECT_THREAD = 'Thread Select';
         export interface SelectThreadAction extends Action {
         thread: Thread;
     }
     export const selectThread: ActionCreator<SelectThreadAction> =
         (thread) => ({
             type: SELECT_THREAD,
             thread: thread
         });
    

    chọn current thread trong reducer

        // Select a particular thread in the UI
        case ThreadActions.SELECT_THREAD: {
          const thread = (<ThreadActions.SelectThreadAction>action).thread;
          const oldThread = state.entities[thread.id];
    
          // mark the messages as read
          const newMessages = oldThread.messages.map(
            (message) => Object.assign({}, message, { isRead: true }));
    
          // give them to this new thread
          const newThread = Object.assign({}, oldThread, {
            messages: newMessages
          });
    
          return {
            ids: state.ids,
            currentThreadId: thread.id,
            entities: Object.assign({}, state.entities, {
              [thread.id]: newThread
            })
          };
        }
    
        default:
          return state;
      }
    };
    

    Chúng ta sẽ bắt đầu với với thread-to-select và sử dụng thread.id đó.
    chúng ta cũng cần copy tất cả các tin nhắn cũ và set trạng tháng isRead = true và trả về 1 state mới.

    Tổng kết

    Trên đây mình đã trình bày về cấu trúc của ứng dụng chat, các thành phần liên quan đến redux như action creator, reducer. Trong phần tiếp theo mình sẽ trình bày việc xây dựng angular chat app để tạo thành 1 ứng dụng hoàn chỉnh
    Cảm ơn các bạn đã chú ý theo dõi
    Chi tiết các ban có thể xem thêm tại cuốn sách: ng-book 2, Felipe Coury, Ari Lerner, Nate Murray, & Carlos Taborda
    Nguồn: Viblo


Hãy đăng nhập để trả lời
 

Có vẻ như bạn đã mất kết nối tới LaptrinhX, vui lòng đợi một lúc để chúng tôi thử kết nối lại.