Redux-toolkit으로 To-do-list 만들기

호두·2022년 7월 26일
1

Toy-project

목록 보기
2/2

카운터 예제는 너무 식상해서 todolist를 redux-toolkit으로 만들어 봤다.

리덕스 툴킷을 이용하려면 또 설치를 해야한다....

npm install redux react-redux @reduxjs/toolkit

1. Store 생성하기

props 노가다를 피하기 위한 store를 생성해보자
나는 redux라는 폴더에 store.js를 생성했다.

src/redux/store.js

import {configureStore} from '@reduxjs/toolkit'
import todoSlice from './todoSlice'

export default configureStore({
    reducer : {
        todo : todoSlice
    }
})

configureStore 로 store를 생성해준다.
객체 형태의 인자에는 reducer가 꼭 있어야한다.


2. Store 와 index 연결 , Provider 설정하기

스토어를 생성 해줬으니 index.js에 store를 연결시켜주자

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 store from './redux/store'
import { Provider } from 'react-redux';

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

reportWebVitals();

import 마지막 두줄을 잘 확인하자 storeProvider
Provider가 App을 감싸고 있고 store라는 파라미터를 전달해준다.
설정을 안해주면 하위 컴포넌트에 상태값이 전달되지 않는다.


3. slice 만들기

slice 는 리듀서와 액션 생성함수 등의 기능을 제공해주는 객체이다.
createReducer 와 createAction의 할일을 해준다는것이다.
리듀서의 이름을 정하고 createSlice로 지정해준다.

  • name은 리듀서 이름
  • initialState 는 데이터 초기값 object형식으로 key / value 형식으로 하면 된다.
  • reducers 에는 액션 형식을 지정해 줄 수 있다.

add는 할 일 입력창에 입력되는 텍스트를 값에 추가해준다.
remove는 선택된 할 일을 제외한 모든 할 일들을 새로운 객체로 리턴해준다.
complte는 선택된 할 일을 true값 으로 변경시켜준다.

src/redux/todoSlice.js

import {createSlice} from '@reduxjs/toolkit'

let nextId =0;
const initialState = [];

export const todoSlice = createSlice({
    name : 'todofunction',
    initialState,
    reducers:{
        add : (state,action) => {
            nextId++;
            state.push({
                id : nextId,
                text : action.payload,
                complete : false,
            })
    },   
    remove : (state, action) =>{
        return state.filter(e => e.id !== action.payload)
    },

    complete : (state, action) =>{
        return state.map(e => e.id === action.payload ? {...e, complete : !e.complete} : e)
    }


}
})

export const {add , remove, complete} = todoSlice.actions 
//store에서 add, remove, complte 액션을 내보낸다.
export default todoSlice.reducer

마지막 export 두줄도 필수다!!

4. 하위 컴포넌트와 연결하기

todolist를 입력하고 추가해주는 form 컴포넌트와 todolist를 보여주는 컴포넌트가 필요하다.
InputTodo.js 와 TodoList.js를 components 폴더에 생성해주자

src/components/InputTodo.js

import React, {useState} from 'react'
import {useDispatch  } from 'react-redux'
import {add} from '../redux/todoSlice'
import s from './InputTodo.module.css'

export default function InputTodo() {
    const dispatch = useDispatch()

    const [todolist, setTodolist] = useState(
    {
        id : 0,
        text : "",
    }
    )

    function handleText(e) {
        setTodolist({text : e.target.value})
    }

    function onReset () {
        setTodolist({text : ""})
    }
  
    
  return (
      <div className={s.InputTodo}>
      <form onSubmit={(e) => {
        e.preventDefault()
        if(todolist.text !== ""){dispatch(add(todolist.text))}
        else(alert("할 일을 입력해주세요!"))
        onReset()
        }}>
            <div>
            <input className={s.textbar} type="text"  
            value = {todolist.text} onChange={handleText}></input>
            <input className={s.submitbutton} type="submit" value="+"></input>
            </div>
        </form>
      </div>

    )
}

useState를 사용하여 todolist라는 state를 만들어주고,
submit 버튼을 클릭 or 엔터키를 치면 dispatch를 통해 todolist.text 값을 넘겨준다.


/src/components/TodoList.js

import React from 'react'
import {useSelector, useDispatch } from 'react-redux'
import { remove , complete } from '../redux/todoSlice'
import s from './TodoList.module.css'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTrashCan } from '@fortawesome/free-solid-svg-icons'


export default function TodoList() {
    const todolist = useSelector(state => state.todo)
    const dispatch = useDispatch()

    const trash = <FontAwesomeIcon icon={faTrashCan} />


    console.log(todolist)

    const todolistView = todolist.map((todo, idx) => (
        
    <li className={s.list}key={todolist[idx].id}>
        <input className={s.checkbox} type="checkbox" 
        onChange={()=> dispatch(complete(todolist[idx].id))}/>
        <div className={s.todolist}>{todo.complete === false ? <>{todo.text}</> : <del>{todo.text}</del>}</div>
        <button className={s.deleteBtn} type="button" onClick={() => dispatch(remove(todolist[idx].id))}>{trash}</button>
    </li> 
    )
    )


  return (
      <>
     <ul>{todolistView}</ul>   
      </>
  )
}

useSelector를 import 해준다.
useSelector를 이용해야 리듀서에 있는 state에 접근 할 수있다.
removecomplete 액션을 불러올거다.

checkbox 버튼과 휴지통 버튼을 누르면 dispatch()로 리듀서에 id값을 넘겨 remove와 complete 액션을 통해 새로운 값을 반환해준다.


작동 확인하기

profile
Front-end

0개의 댓글