액션 타입 - 다른 리덕스 모듈과 겹치지 않게 하기 위해 컴포넌트 이름의 접두사를 앞에 붙여줘야 한다
counter/SET_DIFF
액션 생성함수 -액션객체를 리턴해주는 함수. (export로 내보내기)
리듀서 - 컴포넌트 이름으로 만들어지며 state 파라미터에 디폴트 초기값을 지정합니다.
(export default로 내보내기)
state=initialState
모듈들을 관리해 줄 modules폴더를 만들고 그 안에 모듈들을 만들어준다.
modules/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;
}
}
modules/todos.js
//액션타입선언
const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_TODO = 'todos/TOGGLE_TODO';
//액션 생성 함수
let nextId = 1
export const addTodo = (text) =>({
type:ADD_TODO,
todo:{id:nextId,text: text,done:false}
})
export const toggleTodo = (id)=>({
type:TOGGLE_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 )
default:
return state
}
}
modules/index.js rootreducer 만들기
import { combineReducers } from "redux";
import counter from "./counter";
import todos from "./todos";
//한프로젝트에 리듀서가 여러개일때 하나로 합쳐서 사용 => rootreducer 루트리듀서
//combinereducers( )
const rootReducer = combineReducers(
{
counter:counter,
todos:todos
}
)
export default rootReducer
스토어 생성하기
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 { legacy_createStore as createStore } from 'redux';
import rootReducer from './modules';
import { Provider } from 'react-redux';
import { devToolsEnhancer } from '@redux-devtools/extension'; // 크롬확장 redux devtools
//스토어 만들기
const store = createStore(rootReducer,devToolsEnhancer());
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<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();
store를 만들고 Provider로 묶어줘야 하위 컴포넌트에서 store요소를 불러서 사용할 수 있다.
이제 이 값들을 불러서 화면을 구성하고 상태값을 변경해 줄 컴포넌트를 만들어주면 된다.
컴포넌트 만들기
1. 프레젠테이셔널 컴포넌트
실제 보이는 태그들을 만들어주는 컴포넌트, redux스토어에 직접 접근하지 않음 필요한 값은 props로 받아와서 사용하는 컴포넌트, 주로 UI를 선언하는 것에 집중
2. 컨테이너 컴포넌트
프레젠테이셔널 컴포넌트를 감싸고 store에 접근해서 값을 props로 프레젠테이셔널로 전달. 리덕스 스토어의 상태를 조회하거나, 액션을 디스패치 할 수 있는 컴포넌트. 프리젠테이셔널 컴포넌트를 불러와서 사용
꼭 이렇게 만들어줄 필요는 없지만 기능적으로 분리해 주면 나중에 에러가 났을 때 찾기 편하다
화면을 구성해 주는 요소들이 들어있고 필요한 값들은 props로 컨테이너 컴포넌트한테서 받아온다.
2. 컨테이너 컴포넌트
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());
const onDecrease = ()=>dispatch(decrease());
const onsetDIFF = (diff) => dispatch(setDIFF(diff));
return (
<Counter number={number} diff={diff} onIncrease={onIncrease} onDecrease={onDecrease} onsetDIFF={onsetDIFF}/>
);
};
export default CounterContainer;
컨테이너 컴포넌트에서 Counter컴포넌트를 불러서 사용하고 Props로
함수=dispatch(액션생성함수)와 상태값을 보내주고 있다.
App.js에서 CounterContainer 컴포넌트를 불러서 사용하면 끝
redux자체는 그렇게 되게 어렵지는 않은데 이번에 redux를 배우면서 새로운 개념들을 같이 배워서 이해하기가 정말 너무 힘들었다. 모듈을 다 나눠서 만들고 합쳐서 하나로 만들고 액션객체도 일일이 만들어줬었는데 이번에는 액션객체를 만드는 함수를 만들어서 사용하니 갑자기 연결된 애들이 많아져서 뭐가 어디서 불러서 쓰고 어디에 들어간게 맞는건지 구분을 못해서 수업시간에 좀 힘들었다.. 그래도 redux는 많이 사용하고 있다고하니 연습해서 꼭 잘 쓰고싶다.. 포기하지말자.. 수료 2달남았다.. ㅠㅠ