Redux가 뭔데?

올챙이·2024년 8월 19일

ImpoliteChatbot

목록 보기
3/7
post-thumbnail

Intro

기본적인 레이아웃 작업이 끝나서 상태관리 작업을 할 단계가 왔습니다.
처음 생각난건 useState였지만, 너무 많이 사용해봤기 때문에 다른 기술을 사용하고 싶었습니다.
구글링해보니 리액트의 상태관리로 redux가 널리 알려져있다고 하는데
처음엔 useReducer인줄 알았지만 둘이 다른거라고 합니다.
결론: redux로 결정!!!

Redux 설치

1
npm install redux react-redux
cs

Redux 적용

상태관리하기 전의 코드는 다음과 같습니다.
QuestionInput는 현재 사용자가 입력할 내용을 뜻합니다. 먼저, QuestionInput를Redux로 상태관리 해주겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import {
    ChatContainer,
    ChatElement,
    Chating,
    Chatbot,
    Profile,
    Answer,
    User,
    Question,
    ChatSend,
    QuestionInput,
    SendImg,
} from "./ChatPage.style.js";
 
const ChatPage = () => {
    return (
        <>
            <ChatContainer>
                <ChatElement>
                    <Chating>
                        <Chatbot>
                            <Profile src='/image/Impolite_chatbot.png' alt='챗봇 프로필' />
                            <Answer>무슨 고민 있음?</Answer>
                        </Chatbot>
                        <User>
                            <Question>나 회사 상사 때문에 너무 스트레스 받아</Question>
                        </User>
                    </Chating>
                    <ChatSend>
                        <QuestionInput placeholder='Chatbot에게 하고싶은 말을 입력해주세요!' />
                        <SendImg src='/image/Send.png' alt='화살표' />
                    </ChatSend>
                </ChatElement>
            </ChatContainer>
        </>
    );
};
 
export default ChatPage;
cs

폴더 구조는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
src/
|-- redux/
|   |-- store.js
|   |-- actions.js
|   |-- reducer.js
|-- pages/
|   |-- ChatPage.js
|   |-- ChatPage.style.js
|-- index.js
 
cs
  • store.js

    Redux에서 애플리케이션의 전체 상태를 관리하는 store를 생성하는 코드입니다.

    1
    2
    3
    4
    5
    6
    7
    import { createStore } from "redux";
    import rootReducer from "./reducer";
     
    const store = createStore(rootReducer);
     
    export default store;
     
    cs
    • createStore : Redux에서 제공하는 함수로, 스토어를 생성해주는 역할을 합니다.

    • rootReducer : 이전에 작성한 리듀서를 가져옵니다.

    • const store = createStore(rootReducer) : rootReducer를 인수로 전달하는 스토어를 생성해줍니다.

  • 현재 reducer.js에는 rootReducer이라는게 없는데 왜 rootReducer을 사용하며, 어째서 오류없이 작동하는걸까?

현재 reducer.js에서는 하나의 모듈만 내보내지고 있는 상태입니다. JavaScript에서는 파일을 import할 때 그 파일 내부에 하나의 모듈만 존재한다면 이름을 자유롭게 지정할 수 있습니다.

rootReducer은 Redux에서 관습적으로 사용하는 이름입니다. 굳이 이 이름이 아니라도 상관은 없지만 다른 분들 코드를 살펴보니 rootReducer을 주로 사용하는 것 같습니다.

  • action.js

    Redux에서 상태를 업데이트하기 위해 사용되는 액션 생성자(액션을 만드는 함수)입니다.

    1
    2
    3
    4
    export const setQuestionInput = (input) => ({
        type: "SET_QUESTION_INPUT",
        payload: input,
    });
    cs
    • setQuestionInput : 이름

    • input : 받는 인수

    • "SET_QUESTION_INPUT" : 액션이 어떤 일을 하는지 설명

    • input : 추가 정보

      1
      2
      3
      4
      5
      6
      //결과
      {
          type: "SET_QUESTION_INPUT",
          payload: "유저가 입력한 텍스트"
      }
       
      cs
  • reducer.js

    Redux에서 애플리케이션의 상태를 관리하는 핵심 부분인 reducer를 정의하는 코드입니다.
    이 코드에서는 'SET_QUESTION_INPUT'이라는 액션이 들어오면 'questionInput' 값을 업데이트 해줍니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const initialState = {
        questionInput: "",
    };
     
    const reducer = (state = initialState, action) => {
        switch (action.type) {
            case "SET_QUESTION_INPUT":
                return {
                    ...state,
                    questionInput: action.payload,
                };
            default:
                return state;
        }
    };
     
    export default reducer;
     
    cs
    • initialState : 처음 만들어질 때 가질 기본 상태를 정의

    • reducer : 현재 상태와 액션을 받아 새로운 상태를 반환해줍니다.

    • state = initialState : 리듀서가 처음 호출될 때 state가 정의되지 않은 경우 initialState를 기본값으로 사용합니다.

    • swith 문

      1
      2
      3
      4
      5
      6
      7
      8
      9
       switch (action.type) {
              case "SET_QUESTION_INPUT":
                  return {
                      ...state,
                      questionInput: action.payload,
                  };
              default:
                  return state;
          }
      cs
      • switch문을 사용하여 액션의 type에 따라 어떤 상태 업데이트를 할지 결정합니다.

      • 여기서 action.type는 액션 객체에서 보내준 type입니다.
        ex) type: "SET_QUESTION_INPUT"

      • case가 "SET_QUESTION_INPUT"일 때 실행될 수 있도록 구현해줍니다.

      • '...state'는 현재 상태를 복사하는 코드입니다. 상태의 다른 속성들이 손상되지 않도록 기존 상태를 유지하면서 일부 속성만 업데이트하기 위해 사용합니다.

      • questionInput: action.payload은 questionInput 속성을 action.payload로 업데이트하는 코드입니다.

      • default는 만약 현재의 switch문에 해당하는 case가 없을 경우 현재 상태를 그대로 반환하도록 해줍니다.

  • chatPage.js

    QuestionInput에 입력을하고 enter(또는 sendImg)를 클릭할 때 콘솔창에 나오도록 구현했습니다. 화질이 좀 안좋네요..😥

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    import {
        ChatContainer,
        ChatElement,
        Chating,
        Chatbot,
        Profile,
        Answer,
        User,
        Question,
        ChatSend,
        QuestionInput,
        SendImg,
    from "./ChatPage.style.js";
    import { useSelector, useDispatch } from "react-redux";
    import { setQuestionInput } from "../../redux/actions";
     
    const ChatPage = () => {
        const questionInput = useSelector((state) => state.questionInput);
        const dispatch = useDispatch();
     
        const handleSend = () => {
            console.log(questionInput);
            dispatch(setQuestionInput(""));
        };
     
        const handleKeyDown = (e) => {
            if (e.key === "Enter") {
                handleSend();
            }
        };
     
        return (
            <>
                <ChatContainer>
                    <ChatElement>
                        <Chating>
                            <Chatbot>
                                <Profile src='/image/Impolite_chatbot.png' alt='챗봇 프로필' />
                                <Answer>무슨 고민 있음?</Answer>
                            </Chatbot>
                            <User>
                                <Question>나 회사 상사 때문에 너무 스트레스 받아</Question>
                            </User>
                        </Chating>
                        <ChatSend>
                            <QuestionInput
                                value={questionInput}
                                onChange={(e) => dispatch(setQuestionInput(e.target.value))}
                                onKeyDown={handleKeyDown}
                                placeholder='Chatbot에게 하고싶은 말을 입력해주세요!'
                            />
                            <SendImg onClick={handleSend} src='/image/Send.png' alt='화살표' />
                        </ChatSend>
                    </ChatElement>
                </ChatContainer>
            </>
        );
    };
     
    export default ChatPage;
     
    cs
    • useSelector : 리덕스 스토어에서 상태를 선택해서 가져오는 데 사용됩니다.

      1
      const questionInput = useSelector((state) => state.questionInput);
      cs
    • useDispatch : 리덕스 스토어에 액션을 보낼 때 사용됩니다.

      1
       const dispatch = useDispatch();
      cs
profile
깃허브: https://github.com/sojeong0302

0개의 댓글