상세 컨텐츠

본문 제목

React(리액트) 티키타카 21 (Redux -1)

React

by e7e 2025. 3. 4. 00:14

본문

상태관리가 복잡해지고, 규모가 커질 때는 redux를 쓴당.

 

어렵다기 보다는 프레임워크 처럼 세팅 과 사용방식에 익숙해지는 것이 뽀인또인데,

초보자에게는 상당히 아주 상당히 낯선 느낌이 문제당.

낯선 그 느끼미 게으른 뇌에 이건 헷깔리꽁 어렵넹! 이라는 잘못된 결론을 내려버린당.

 

마치 눈 앞에 오르지 못할 정도로 높아 보이는 산이 있는데, 가보면 땀 좀 빼면 되는데,

게으른 뇌가 산 입구에서 막걸리나 한잔 할까라고 유혹의 두 손을 마구 흔들어 된당.

 

이런 경우에는 헷갈리지 않게  자신만의 순서(꼭 추천 순서가 아니어도 당근 됨!)를

정해서 몇번 반복해서 손과 눈의 콜라보를  먼저 성취하는 거이 좋을 지어다.

useReducer를 이전에 사용해 본 경험이 있다면 많은 도움이 될꺼당.

상태(state),  리듀서(reducer), 디스패치(dispatch), 액션(action)이 떠올라야만 한당. 

 

0. 사전준비 

 디렉토리를 1개 만들고, 해당 디렉토리에 아래 명령어로 vite 프로젝트를 생성하고,

 react / javascript를 선택하장.(typescript는 관심 외 코드 가 더 필요해서 여기선 회피한당.) 

 tailwindcss 설정은 되어 있다 가정하겠당.

npx create-vite@latest .

 

1. 설치

npm install @reduxjs/toolkit react-redux

 

2. store 생성

 store는 app당 1개만 있는걸 권장 한당. 그리하여 관례적으로 src 아래에  app 폴더를 만들고,

 그 안에 store.js를 일단 아래 처럼 만든당. 

 

store.js

import { configureStore } from "@reduxjs/toolkit"

const store = configureStore({
  reducer:{    
  }
})

export default store

 

3. provider 생성

 main.jsx에 아래 처럼 Provider를 제공하고, store를 연결시키자.

 이제 Provider로 둘러싸인 App에 들어가는 컴포넌트는 store에 다이렉트로 접근할 수 있다.

 Props Drilling이 아니고, 중앙 관리가 핵심이당.

 

main.jsx

import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { Provider } from 'react-redux'
import store from './app/store.js'

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

 

4. slice 생성

  slice는 store(가게)에 가면  상품을 분류해서 코너별로 나열한다.  코너는 1개~여러개당.

  그런 코너와 비슷하게 데이터를 분류한 코너를    slice라 생각하면 좋을 것 같당.

  Redux에서 slice는 reducer와 action creator의 통합으로 보면 좋당.

 

  slice를 만들 땐 보통 features란 폴더를 만들고, 그 안에서 폴더를 만들어서 분류한다.

  features 안에 friends란 폴더를 만들고,  friendSlice.js 파일을 아래 처럼 맹글장

 

 friendSlice.js

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  friends: [
    { id: 1, name: "경미니", song: "그리 미누", color:"green" },
    { id: 2, name: "로제", song: "ground", color:"black" },
    { id: 3, name: "원영", song: "iam" , color:"gold"},
    { id: 4, name: "제니", song: "mantra" , color:"pink"},
    { id: 5, name: "카리나", song: "nova" , color:"blue"}
  ]
}

// slice 만들어 수출
export const friendSlice = createSlice({
  name: "friend",
  initialState,
  reducers: {
    addFriend: (state, action) => { 
      state.friends = [action.payload, ...state.friends]
    }
  },
  extraReducers:()=>{}
})

// action 추출하여 수출
export const { addFriend } = friendSlice.actions
// reducer 디폴트 수출
export default friendSlice.reducer

 

 

5. slice를 store에 등록

 

store.js

import { configureStore } from "@reduxjs/toolkit"
import  friendReducer from "../features/friends/friendSlice"

const store = configureStore({
  reducer:{ 
    "friend": friendReducer   
  }
})

export default store

 

6. useSelector 와 useDispatcher 사용

여기까지 왔던 이유당. 세팅만 잘 되어 있다면,

useSelector와 useDispatcher를 이용해서 어디서든 편하게 쉽게 상태 변경이 가능하당.

 

App.jsx

import { useDispatch, useSelector } from "react-redux"
import { addFriend } from "./features/friends/friendSlice";
import { useRef } from "react";

function App() {
  const { friends }  = useSelector(state => state.friend)
  const dispathch = useDispatch();
  const myForm = useRef();

  const addNew = (e)=>{
    e.preventDefault();
    const formData = new FormData(myForm.current)
    dispatch(addFriend({
       id:friends[friends.length -1].id+1,
       name:formData.get("fname"),
       song:formData.get("fsong"),
       color:formData.get("fcolor")
    }))
    
    // 입력 값들 초기화
    myForm.current.fname.value = "";
    myForm.current.fsong.value = "";
    myForm.current.fcolor.value = "#000000";

  }
  return (
    <>
     <h1 id="title">리덕스 연습</h1>
     <hr />
     <form ref={myForm} onSubmit={addNew}>
       이름 <input type="text" autoFocus name="fname" required /><br /> 
       노래 <input type="text"  name="fsong" required /><br />
       칼라 <input type="color" name="fcolor" /><br />
       <button type="submit">추강</button> 
     </form>
     <hr/>
     <div>
        {
          friends.map(friend => (
            <div key={friend.id} className="friend">
               <h1>{friend.name}</h1>
               <h2 style={{color:friend.color}}>{friend.song}</h2>
            </div>
          ))
        }
     </div>
     </>
  )
}

export default App

 

7. style

 이거슨 덤이당. 아마 화면이 정말 못 생겨서 화가 날거당.

 아래는 내가 할 수 있는 나름 최선임을 난 부정하지 못한당. 받아들이장.

 

 index.css

@import "tailwindcss";

#title {
  @apply text-3xl
}

hr {
  @apply border-4 m-2
}

input[type=text] {
  @apply border-2 border-gray-400 mb-1
}

button {
  @apply rounded border-1 w-20 ml-20
}

.friend {
  @apply border-amber-400 border-4 mb-5 text-center
}

 

결과는 나의 경우 아래 처럼 보인당.  역시  디자인은 훌륭하지 못하당.

 

여기까지 했다면 훌륭하당. 하지만

Redux는 여기서 끝은 아니당.  Redux는 비동기를 처리하는 방식도 제공하는데

(물론 useEffect를 잘 사용한다면 그걸로 처리 할 수동 있당.)

slice 코드에  있는 extraReducers 와 createAsyncThunk 함수를 이용해야 하는데..

오늘은 여기까지만으로도 훌륭하니, 보고 또 보고,  다음글에서 또 보장

 

혹 시간이 풍년이라면(데이트 신청에 까였다거나, 실연의 아픔이 깊거나,

  산삼을 먹어서 잠이 오지 않거나, 갑자기 영어 공부 생각이 난다거나 등등...)

괘니 아래 링크도 가서 읽어 보장.

https://redux-toolkit.js.org/tutorials/quick-start   

 

 


 

로제(rosie)는 현존 내가 가장 좋아하는 음색을 가졌당.

귀는 프리 패스하고 , 심장을  직격 찌리릿 번개 지지미 핵 태우미당.

 

그럼에도  내게 number one girl은 아닐 girl.~~

number one girl? Who are you?  =>   ??Jean 

 

그럴 girl! 반복(repeat)은  세뇌를 부른다. 

number one 일 girl!! , 넌 number one이 아닐 girl!!~~ 

 

number one을  또 만들고 또 만들어 number one group 장부를 만들자~

커지고 커지면 대 장부당!~~

역시 모든 글은 아무말 대잔치로 끝날 girl !!

 

https://www.youtube.com/watch?v=qCepOLkcF_A

 

관련글 더보기