React

리덕스 작동원리 알아보기_FC

jennyiscoding 2022. 8. 1. 00:24

처음부터 리덕스 프로젝트로 만들기 

npx create-react-app my-app --template redux 

 

작동원리 : 

1. dispatch함수를 실행한다. 이 함수를 실행하면 이 안에 action생성함수를 넣을 수 있다. 

2. 액션을 발생시킨다. 

3. 액션은 리듀서라는것을 통해 어딘가로 전달이 되고 전달된 리듀서로인해

4. 최종적으로 상태가 바뀐다. 

 

다운로드 : npm install react-redux redux

src폴더에 store폴더 -> index.js, modules폴더-> todo.js 를 만들어준다. 

store : app에서사용되는 최상위 저장소. 여기서 결국 합쳐줄 것이다. 

 

첫번째로, todo.js

작동원리를 한번 더 살펴보자면, 

1.디스패치 함수는 액션을 불러올 것이다. 

2.그 액션은 리듀서를 호출하고 

3.리듀서는 최종적으로 스토어를 변경시킨다. 

 

todo.js에서는

-우리가 원하는 행동, 데이터의 변화를 각각의 액션으로 할당해줄 것이다. 

 

먼저, store폴더의 modules -> todo.js를 열어준다. 

아래 코드에서 리덕스 액션, 스토어, 리듀서를 만들어주었다. 

 

todo.js코드 : 

const CREATE = "todo/CREATE";
const DONE = "todo/DONE";

//액션 생성 함수
export function create (payload){
    return{
        type: CREATE,
        payload,
    }
}

export function done (id){
    return{
        type: DONE,
        id,
    }
}

//초기 상태 
const initialState = {
    list: [
        {
            id: 0,
            text: '척추펴기',
            done: true
        },
        {
            id: 1,
            text: '물마시기',
            done: false
        },
    ]
}

//리듀서를 만들어서 스토어를 변경시켜주겠다
export default function todo(state= initialState , action){
    switch (action.type){
        case CREATE : 
            return{
                ...state,
                list: state.list.concat({
                  id : action.payload.id,
                  text : action.payload.text
                })
            }
        case DONE : 
            return{
                ...state,
                list: state.list.map(item =>{
                    return item.id === action.id ? {...item, done:true} : item;
                })
            }
        default : 
            return state;
    }
}

다음으로 루트리듀서를 만들어보겠다. 

리듀서를 합쳐주는 역할을 한다. 

index.js코드 : 

import {combineReducers} from "redux";
import todo from "./modules/todo";

export default combineReducers({
    todo//서브리듀서라고 부른다. 
});

//이 스토어는 루트 리듀서가 된다.

이 다음 index.js에서 리덕스를 위한 코드를 써보겠다. 

최상단의 index.js코드 : 

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import {createStore} from "redux";
import rootReducer from './store';
import {Provider} from 'react-redux';

const devTool = window.__REDUX_DEVTOOLS_EXTENSTION__ && window.__REDUX_DEVTOOLS_EXTENSTION__(); // 리덕스 대브 툴스 쓰기위해 써넣음. 
const store = createStore(rootReducer, devTool);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

reportWebVitals();

이제 실제 컴포넌트를 만들어보자. 

컴포넌트 폴더 추가했다! 

AllTodoList.js

export default function AllTodoList(){
    const list = [
        {
            id: 0,
            text: '척추펴기',
            done: true
        },
        {
            id: 1,
            text: '물마시기',
            done: false
        },
    ]

    return (
        <section>
            <h1>할일목록</h1>
            <div>
                <input type="text"/>
                <button>확인</button>
            </div>
            <ul>
                {list.map( item => (
                    <li key={item.id}>{item.text}</li> 
                ))}
            </ul>
        </section>
    )
}

DoneList.js

export default function DoneLiest() {
    const list = [];
    return (
        <section>
            {list.length > 0 && <h1>완료된 목록</h1>}
            <ul>
                {list.map(item => <li key={item.id}>{item.text}</li>)}
            </ul>
        </section>
    );
}

이 뼈대에 스토어, 리듀서랑 이어줘보자. 

AllTodoList.js

import { useRef } from "react";
import {useDispatch, useSelector} from "react-redux";
import {create, done} from "./../store/modules/todo";

export default function AllTodoList(){
    const list = useSelector((state)=> state.todo.list).filter(
        (item)=> item.done === false
    );

    const inputRef = useRef();
    const dispatch = useDispatch();

    return (
        <section>
            <h1>할일목록</h1>
            <div>
                <input type="text" ref={inputRef}/>
                <button onClick={()=>{dispatch(create({id: list.length, text:inputRef.current.value}))}}>확인</button>
                
            </div>
            <ul>
                {list.map(item => (
                    <li key={item.id}>{item.text}
                    <button onClick={()=>dispatch(done(item.id))}>완료</button>
                </li> 
                ))}
            </ul>
        </section>
    )
}

 

DoneList.js

import {useDispatch, useSelector} from "react-redux";
import { done } from "../store/modules/todo";


export default function DoneLiest() {
    const dispatch = useDispatch();
    const list = useSelector((state)=> state.todo.list).filter(
        (item)=> item.done === true
    );
    return (
        <section>
            {list.length > 0 && <h1>완료된 목록</h1>}
            <ul>
                {list.map(item => 
                    <li key={item.id}>
                        {item.text}
                    </li>
                )}
            </ul>
        </section>
    );
}