React 상태-(3): Redux

김수민·2023년 1월 26일
0

React

목록 보기
12/17

Redux

Redux는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너
useState : 간단한 상태 업데이트
useReducer : dispatch 함수를 이용한 상태 업데이트

규칙

  1. 하나의 애플리케이션 안에는 하나의 스토어가 있다.
  2. 상태는 읽기 전용이다.
  3. 리듀서는 순수한 함수여야 한다.

장점

리덕스를 쓰면
1. store를 만들어서 상태를 관리할 수 있다.
2. devtools를 써서 상태를 확인할 수 있다.
3. middleware를 사용할 수 있다.


JS

1. 리듀서 작성하기

function reducer(state,aciton){
	return 새로운state값;
} 

2. 스토어 생성하기

하나의 스토어를 작성한다.
스토어 안에는 현재의 상태, 리듀서와 내장함수 dispatch(), subscribe(), getState()가 있다.

const store= Redux.createStore(reducer함수)

<Provider store={store}>
  	<App/>
<Provider>

store를 전역에서 사용할 수 있도록 Provider로 감싼다.

3. 상태값 사용하기

store.getState()

4. 상태값 변경하기

type 속성을 가진 객체인 action을 전달한다.
이 외의 속성을 추가할 수도 있다.

store.dispatch({
	type: '타입명'
})

액션

액션을 만들어주는 함수 작성하여 상태값 변경 시 아래와 같이 변경할 수 있다.

function increment(){
	return{
      type: "INCREMENT",
      add: add
    }
};
store.dispatch(
	increment(5)
);

5. 구독하기

store가 업데이트 되면 함수를 다시 호출한다.

		store.subscribe(호출할 함수);

예시

<head>
	src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script>
</head>

<body>
	<h1 id="number">0</h1>
	<button id="increment">+</button>
	<button id="decrement">-</button>
  
  <script>
        const numberEle= document.querySelector("#number");
        const btnIncerment= document.querySelector("#increment")
        const btnDecerment= document.querySelector("#decrement")
      
        
        // 초기값 설정	
		const initialState={
			num: 0
		}
		// 1. reducer 함수 만들기
		function reducer(state=initialState,action){
			switch(action.type){
				case 'INCREMENT':
				return{
					num: state.num+1
				};
				case 'DECREMENT':
				return{
					num: state.num-1
				};
				default:
				break;
			}
		}

		// 2. store 생성
		const store= Redux.createStore(reducer);
            // 상태가 변경될 때 마다 호출시킬 함수
			const render=()=>{
				numberEle.innerHTML= store.getState().num;
			}

		// 3. 구독하기 : store가 업데이트 되면 (render)함수를 다시 호출
		store.subscribe(render);

		// 이벤트 지정
		btnIncerment.addEventListener("click",()=>{
			store.dispatch({type:"INCREMENT"});
		});
		btnDecerment.addEventListener("click",()=>{
			store.dispatch({type:"DECREMENT"});
		});

	</script>
  
</body>

React

npm install reduxnpm install react-redux npm install redux-thunk npm install @redux-devtools/extension 이 되어있음을 기반으로 한다.

1. redux 모듈 생성

액션 타입, 액션 생성함수, 리듀서가 모두 포함되어있는 JS 파일을 생성한다.

// action type 만들기 : redux module
const SET_DIFF=  "counter/SET_DIFF";
const INCREMENT= "counter/INCREMENT";

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

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

// reducer 선언
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
			};
		default:
			return state;
	}
}

리듀서 합치기 combineReducers()

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

// 여러개의 useReducer를 한개로 합치기
const rootReducer= combineReducers({
	counter: counter,
	todos: todos
})

export default rootReducer;

2. 스토어 생성

[index.js]
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import rootReducer from './modules';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

// 스토어 생성
const store= createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
	// App을 Provider로 감싸고 생성한 스토어를 props로 전달한다.
    <Provider store={store}>
    <App/>
    </Provider>
  </React.StrictMode>
);

reportWebVitals();

❗ createStore 작성시 취소선이 그어질 수 있으나 정상적으로 작동된다.
이 취소선을 없애고 싶다면 import 시 import{legacy_createStore as createStore} from 'redux';로 작성한다.

3. 컴포넌트 생성

1. 프리젠테이셔널 컴포넌트
리덕스 스토어에 접근하지 않고 필요한 값은 props로 전달 받아, 화면을 설계하는 컴포넌트

 // 프리젠테이셔널 컴포넌트
 import React from 'react';

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

 export default Counter;

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

 // 컨테이너 컴포넌트
 import React from 'react';
 import { useDispatch, useSelector } from 'react-redux';
 import Counter from '../components/Counter';
 import { increase, setDiff } from '../modules/counter';

 const CounterContainer = () => {
     // redux store의 상태를 조회하는 Hook useSelector
     // useSelector()로 받아온 값에는 모든 redux store 상태가 들어가있다.
     // 이 중 counter에 들어간 값을 받아오고 싶을 경우 리듀서 합치기에서 작성한
     // combineReducers의 key인 counter를 부르면 된다.
     const {number,diff}= useSelector(state=>({...state.counter}));
     const dispatch= useDispatch();
     // 각 액션들을 dispatch하는 함수
     const onIncrease=()=> dispatch(increase());
     const onsetDiff=()=> dispatch(setDiff(diff));
     return (
         <Counter number={number} diff={diff}
         onIncrease={onIncrease} onsetDiff={onsetDiff}
         />
     );
 };

 export default CounterContainer;

Redux DevTools 사용하기

JS

  1. Redux DevTools 다운로드

  2. createStore()의 매개변수로 window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() 입력

  3. 개발자 도구(F12) 👉 Redux로 실행

위와 같이 실행하면 state가 변경될 때마다 action과 state의 변경사항을 안내해준다.

React

  1. Redux DevTools 다운로드

  2. 터미널에서 npm install --save @redux-devtools/extension install

  3. createStore()의 매개변수로 devToolsEnhancer() 입력, import 되는 Hook임

  4. 개발자 도구(F12) 👉 Redux로 실행

위와 같이 실행하면 state가 변경될 때마다 action과 state의 변경사항을 안내해준다.

profile
sumin0gig

0개의 댓글