Redux

hanyoko·2023년 6월 23일

REACT

목록 보기
12/15
post-thumbnail

Redux

자바스크립트 앱을 위한 예측 가능한 상태 컨테이너

useState : 간단한 상태 업데이트
useReducer : dispatch 함수를 이용한 상태 업데이트

규칙

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

useReducer()

  1. 상태초기화
  2. 리듀서함수
  3. 상태와 디스패치 생성
  4. 디스패치({액션})
  • 스토어 생성하기
    const store = Redux.createStore(리듀서함수)
  • 상태값 반환하기
    store.getState()
  • 상태값 변경하기
store.dispatch({
type: "",
})```

액션(Action)

상태를 업데이트 할 때 액션을 전달한다
액션은 객체로 표현되며 type 속성을 필수로 가지고 있다
그외의 속성을 추가할 수 있다

액션객체

{
type: "INCREMENT"
color: "red"
}

액션을 만들어주는 함수이다.

function increment(add){
return {
type: "INCREMENT",
add: add
}
}
const increment = (add) => ({type: "INCREMENT", add: add})

리덕스를 쓰면

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

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>

redux devtools 설치

해당 링크에서 설치할 수 있다.

Redux Devtools 실행

//개발자 도구(F12)에서 도구들이 모여있는 >> 를 클릭하면 찾을 수 있는 Redux를 클릭하여 실행시켜준다.

state가 변경될 때마다 action과 state의 변경사항을 안내해준다.

터미널에서 Redux 설치해주기

npm install redux
npm install react-redux
npm install redux-thunk
npm install --save @redux-devtools/extension


1. redux 모듈 생성

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

// 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. 컴포넌트 만들기

프리젠테이셔널 컴포넌트

리덕스 스토어에 직접적으로 접근하지않고 필요한 값은 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;

컨테이너 컴포넌트

리덕스 스토어의 상태를 조회하거나, 액션을 디스패치 할 수 있는 컴포넌트
다른 프레젠테이셔널 컴포넌트 불러와서 사용

 // 컨테이너 컴포넌트
 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;

!!! 상태관리 !!!

const [state, setState] = useState("green")
const [state, dispatch] = useReducer(reducer, initialState)

dispatch ---> 액션을 발생시키는 함수

redux 사용하기

  • 스토어 생성하기
    const store = Redux.createStore(reducer)
  • 상태값 수정
    store.dispatch ({액션 객체})
  • 상태값 조회
    store.getState()
  • 구독
    store.subscribe(함수)

react-redux

  • react-redux 설치
    npm install react-redux
  • 스토어 리액트 전역에서 사용하기
<Provider store={store}>
<App/>
</Provider>
  • 리덕스 상태 조회하는 Hook 함수
state = 10, state = "green"
state = {
todos: [
{
id: 1,
text: "리덕스"
},
{
id: 1,
text: "리덕스"
}
],
number: 10
}
  • 리덕스 상태 조회하는 Hook 함수
    useSelector(state => state)

  • 디스패치를 반환하는 Hook 함수
    useDispatch ---> dispatch

  • 커스텀훅 + useReducer() 1개

  • 리덕스 1개

할일목록 구현

  1. 컨테이너 컴포넌트
  • TodosContainer.js
  1. 프레젠 테이셔널 컴포넌트
  • Todos.js
  • TodoList.js
  • TodoItem.js

0개의 댓글