Javascript/React

[React] Spring Boot with React 채팅 서버 : 4. redux

noahkim_ 2022. 3. 13. 18:07

/messenger path로 오게될 경우, 서버와의 stomp handshake가 이루어진다.

navigation 컴포넌트에서 최초의 핸드쉐이크 요청을 하며, 이후 채팅방에서 채팅을 하게 될경우도 핸드쉐이크 후

반환받은 stomp client를 재사용하여 채팅하는데 사용한다. 이를 위해 컴포넌트간 전역적으로 stomp client 객체를 공유하여 사용한다.

 

컴포넌트간 전역적 공유 방법에는 여러가지 방법이 있다. 현재 사용하고 있는 swr을 비롯하여 redux 등이 대표적이다

프로젝트간 사용하고 있는 모듈로 진행하는 방식이 일관성있고 좋다. 하지만 stomp client는 단순 데이터가 아니여서 localstorage에 보관하는 방식이 적절하지 않고 json 데이터로 다시 불러오는데도 함수속성을 읽는데 어려움이 있다.

 

이러한 불편함을 해결하기 위해 redux를 도입하였다.

 

1. Redux 개념 정리

Redux란

  • A predictable state container for Javascript apps
  • 하나의 객체 안에는 상태를 가지며, 상태값을 수정하거나 가져올 때 reducer나 dispatcher로만 접근 및 사용이 가능하게 하여
    객체의 상태값을 관리하는 모듈
  • 다른  컴포넌트에게 값을 전달하는데 복잡성이 줄어듬

  • 또한 타임스탬프별 스냅샷이 등록

 

 

 

 

 

 

Redux flow

 

  • store에 데이터를 보관하고 state를 변경할 경우 store를 통해 수정함
  • 미리 정의된 reducer 함수의 동작으로 state를 변경시킬 수 있다
    • dispatch()에서 현재 state와 action 값을 전달받아 값을 변경시키고 새로운 값을 리턴해준다
    • dispatch()는 reducer를 호출하며 현재 state와 action 객체를 전달해주는 역할을 함
      • action은 dispatch()의 parameter이며, action의 값 별로 dispatch()는 동작을 정의함
    • subscribe()는 render가 state 별 구독을 신청하여 값이 바뀔때마다 새로 그려주도록 하는 기능
    • getState()시 render가 값을 가져올 때 사용하는 함수
  • render는 UI를 그리는 컴포넌트를 뜻함

 

2. Redux 적용

store 적용

const App = () => {
    return (
        <React.StrictMode>
            <Provider store={store}>
                <Switch>
                    <Redirect exact path="/" to="/login"/>
                    <Route path="/login" component={LogIn}/>
                    <Route path="/signup" component={SignUp}/>
                    <Route path="/messenger" component={Messenger}/>
                </Switch>
            </Provider>
        </React.StrictMode>
    );
};
  • 루트 컴포넌트에 <Provider store={store}>를 감싸서 리액트 앱에 store를 쉽게 연동할 수 있음

 

store 생성

import {applyMiddleware, createStore} from 'redux'
import rootReducer from "../reducers";
import thunk from 'redux-thunk'

const store = createStore(rootReducer, applyMiddleware(thunk))

export type RootReducerType = ReturnType<typeof rootReducer>

export default store;
  • redux-thunk
    • 리덕스를 사용하는 어플리케이션에서 비동기 작업을 처리할 때 redux-thunk 미들웨어를 사용함
      • 객체가 아닌 함수 형태의 action을 dispatch 할 수 있게 해줌
      • action 생성 함수에서 일반 action 객체를 반환하는 대신 함수를 반환함
    • 이로 인하여 reducer가 action이 dispatch된 다음 reducer에서 해당 action을 처리하기 전 추가작업을 할 수 있다.

 

 

 

action 적용

import {Dispatch} from "react";
import {
    STOMP_GET_FAILURE,
    STOMP_GET_SUCCESS,
    STOMP_SAVE,
    StompDispatchType
} from "./StompActionTypes";

import {Client} from '@stomp/stompjs'

export const fetchStompData = () => (dispatch: Dispatch<StompDispatchType>) => {
    try {
        dispatch({type: STOMP_GET_SUCCESS})

    } catch (err) {
        dispatch({type: STOMP_GET_FAILURE})
    }
}

export const saveStompData = (client: React.MutableRefObject<Client | undefined>): StompDispatchType => ({
    type: STOMP_SAVE,
    payload: client?.current!
})
  • navigation 에서 stomp handshake가 성공하여 client 객체를 리턴받을 경우 store에 save시킴
    • type과 payload 타입을 정의된 형식에 맞게 작성해주고 사용함
  • chatBox 컴포넌트에서 채팅을 할 경우 fetchStompData 함수를 호출하여 stomp client를 가져오도록 한다.

 

  • action type
import {Client} from "@stomp/stompjs";

export const STOMP_GET_SUCCESS = 'STOMP_SUCCESS'
export const STOMP_GET_FAILURE = 'STOMP_FAILURE'
export const STOMP_SAVE = 'STOMP_SAVE'

export type StompType = {
    type: Client
}

export interface saveStomp {
    type: typeof STOMP_SAVE
    payload: Client
}

export interface stompSuccessDispatch {
    type: typeof STOMP_GET_SUCCESS
}

export interface stompFailDispatch {
    type: typeof STOMP_GET_FAILURE
}

export type StompDispatchType =
    saveStomp
    | stompFailDispatch
    | stompSuccessDispatch;

 

reducer 적용

  • rootReducer 생성
import {combineReducers} from 'redux';
import StompReducer from "./StompReducer";

const rootReducer = combineReducers({
    StompReducer
})

export default rootReducer;

 

 

출처 :

생활코딩 redux https://opentutorials.org/module/4078

제로초 블로그 https://www.zerocho.com/category/React/post/57b60e7fcfbef617003bf456