본문 바로가기
react

[React]todolist(redux사용)

by 남민섭 2023. 2. 20.
728x90
반응형

 

 

 

1. 리덕스 모듈 만들기

(액션타입, 액션 생성함수, 리듀서가 포함되어있는 자바스크립트 파일)

 

counter.js  모듈

//액션 타입 만들기
const SET_DIFF = 'counter/SET_DIFF';
const INCREMENT = 'counter/INCREMENT';
const DECREMENT = 'counter/DECREMENT';


//액션 생성 함수 만들기
export const setDiff = (diff) => ({type: SET_DIFF, diff});
export const increase = () => ({type: INCREMENT});
export const decrease = () => ({type: DECREMENT});

//초기상태 선언
const initialState = {
    number: 0,
    diff: 1
}

//리듀서 선언
export default function counter(state = initialState, action) {
    switch(action.type){
        case SET_DIFF:
            return {
                ...state,
                diff: action.diff
            };
        case INCREMENT:
        return {
            ...state,
            number: state.number + state.diff
        };
        case DECREMENT:
        return {
            ...state,
            number: state.number - state.diff
        };
        default:
            return state
    }
}

 

2. rootReducer만들기

(모듈들을 하나로 합쳐서 사용할 수 있음)

modules 폴더 안에

index.js 

//한트로젝트에 여러개의 리듀서가 있을 경우
//한 리듀서로 합쳐서 사용
//합쳐진 리듀서를 루트 리듀서
//combineReducers()====> 리듀서를 합쳐줌!!!!!!!!

import { combineReducers } from "redux";
import counter from "./counter";

const rootReducer = combineReducers({
    counter: counter
})
export default rootReducer;

 

3. 스토어 생성

src 폴더 안에

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import rootReducer from './modules';
import { legacy_createStore as createStore } from 'redux';
import { Provider } from 'react-redux';
import { devToolsEnhancer } from '@redux-devtools/extension';

const store = createStore(rootReducer, devToolsEnhancer())   
//rootReducer modules 두개를 합쳐논거
console.log(store.getState())

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}> 
    {/* provider는 스토어 리액트 전역에서 사용할수 있음 */}
    <App />
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

4. 컴포넌트 만들기

프리젠테이셔널 컴포넌트로 props로 전달해주기 위해서 

리덕스 스토어의 상태를 조회하거나, 액션을 디스패치 할 수 있는 컨테이너 컴포넌트 만들기

containers 폴더 안에

CounterContainer.js

import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Counter from '../components/Counter';
import { decrease, increase, setDiff } from '../modules/counter';

const CounterContainer = () => {
    //useSelector()는 리덕스 스토어의 상태를 조회하는 hook입니다.
    const {number, diff} = useSelector(state=>state.counter);
    
    const dispatch = useDispatch();
    //각 액션들을 디스패치하는 함수
    const onIncrease =()=> dispatch(increase());        //{type: INCREMENT}
    const onDecrease = () => dispatch(decrease());      //{type: DECREMENT}
    const onsetDiff = diff => dispatch(setDiff(diff));  //{type: SET_DIFF, diff}
    return (
        <Counter number={number} 
        diff={diff}
        onIncrease={onIncrease}
        onDecrease={onDecrease}
        onSetDiff={onsetDiff}
        />
    );
};

export default CounterContainer;

프리젠테이셔널 컴포넌트

components 폴더안에

Counter.js

import React from 'react';

const Counter = ({number, diff, onIncrease, onDecrease, onSetDiff}) => {
    const onChange = (e) => {
        onSetDiff(Number(e.target.value))
    }
    return (
        <div>
            <h1>{number}</h1>
            <div>
                <input type = "number" value={diff} min="1" onChange={onChange}/>
                <button onClick={onIncrease}>+</button>
                <button onClick={onDecrease}>-</button>
            </div>
        </div>
    );
};

export default Counter;

카운터 끝!!!!!


todolist 시작

 

1. 리덕스 모듈 만들기

(액션타입, 액션 생성함수, 리듀서가 포함되어있는 자바스크립트 파일)

modules 폴더 안에

todos.js

//액션 타입 선언
const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_TODO = 'todos/TOGGLE_TODO';
const DELETE_TODO= 'todos/DELETE_TODO';

//액션 생성 함수 - 객체리턴
let nextId = 1;
export const addTodo = (text) =>({
    type: ADD_TODO,
    todo: {
        id: nextId++, //새 항목 추가하고 nextId값을 1 더해줌
        text: text,
        done: false
    }
})
export const toggleTodo = (id) => ({
    type: TOGGLE_TODO,
    id: id
})
export const onDeleteTodo = (id) => ({
    type: DELETE_TODO,
    id: id
})
//초기상태 - 초기상태는 배열이어도 되고, 원시타입(숫자, 불리언, 문자열), 객체라도 됩니다.
const initialState = [
    /* {
    id: 1,
    text:"해야할 일",
    done: false
    } */
];
//리듀서
export default function todos(state = initialState, action ) {
    switch(action.type){
        case ADD_TODO:
            return[
                ...state,
                action.todo 
            ]
        case TOGGLE_TODO:
            return state.map(todo => todo.id === action.id ? {
                ...todo, done: !todo.done} : 
                todo
                )
        case DELETE_TODO:
            return state.filter(todo =>todo.id !== action.id )               
        default:
            return state;            
    }
}
//아이디가 일치하면 done 값을 반전시킴 아니라면 그대로둠

2. rootReducer만들기

(모듈들을 하나로 합쳐서 사용할 수 있음)

modules 폴더 안에

index.js   (todos 추가)

//한트로젝트에 여러개의 리듀서가 있을 경우
//한 리듀서로 합쳐서 사용
//합쳐진 리듀서를 루트 리듀서
//combineReducers()====> 리듀서를 합쳐줌!!!!!!!!

import { combineReducers } from "redux";
import counter from "./counter";
import todos from "./todos";

const rootReducer = combineReducers({
    counter: counter,
    todos: todos
})
export default rootReducer;

3. 스토어 생성(counter 만들때 생성 했음)

 

4. 컴포넌트 만들기

프리젠테이셔널 컴포넌트로 props로 전달해주기 위해서 

리덕스 스토어의 상태를 조회하거나, 액션을 디스패치 할 수 있는 컨테이너 컴포넌트 만들기

 

containers 폴더 안에

TodosContainer.js

import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Todos from '../components/Todos';
import { addTodo, onDeleteTodo, toggleTodo  } from '../modules/todos';

const TodosContainer = () => {
    //useSelector로 상태에서 필요한 속성값 반환
    const todos = useSelector(state=> state.todos)
    const dispatch = useDispatch();

    const onCreate = text => dispatch(addTodo(text)) 
    // addTodo는 액션 객체 생성 , modules/todos.js 확인
    const onToggle = id => dispatch(toggleTodo(id))
    const onDelete = id => dispatch(onDeleteTodo(id))
    return (
        <div>
            <Todos todos={todos} onCreate={onCreate} 
            onToggle={onToggle} onDelete={onDelete}/>
        </div>
    );
};

export default TodosContainer;

프리젠테이셔널 컴포넌트

components 폴더안에

Todos.js

import React, { useState } from 'react';
import TodoList from './TodoList';

const Todos = ({onCreate, todos, onToggle, onDelete}) => {
    const [text, setText] = useState('');
    const onChange = (e) => setText(e.target.value);
    const onClick = () => {
        onCreate(text);
        setText('');
    }
    return (
        <div>
            <div>
                <input value={text}
                onChange={onChange}></input>
                <button onClick={onClick}>등록</button>
            </div>
            <TodoList todos={todos} onToggle={onToggle} onDelete={onDelete}/>
        </div>
    );
};

export default Todos;

프리젠테이셔널 컴포넌트

components 폴더안에

TodosList.js

import React from 'react';

const TodoList = ({todos, onToggle, onDelete}) => {
    return (
        <ul>
            {todos.map(todo=><li key={todo.id} 
            onClick={()=> onToggle(todo.id)} style={{textDecoration: todo.done ? 'line-through': 'none'}}>
                {todo.text}
               <button onClick={()=>onDelete(todo.id)}>삭제</button></li>)}    
        </ul>
    );
};

export default TodoList;

 끝!!!!!

728x90
반응형

'react' 카테고리의 다른 글

[react]react-Heroku 서버 배포하기/vercel 웹 배포하기  (0) 2023.03.07
[react]redux-middleware  (0) 2023.02.24
[React]todolist(reducer 사용)  (0) 2023.02.20
[React]Todolist(useState사용)  (0) 2023.01.31
[React]redux  (0) 2023.01.27

댓글