이해하기 위해서 ㄴ반드시 개인적으로 리덕스 코드를 짜볼것...
리엑트는 컴포넌트 기반의 자바스크립트 라이브러리 언어이다.
컴포넌트간 데이터(props)를 부모 -> 자식요소로만 데이터를 전달 가능하다
-> 남발 / 형제간에 전달하려면 -> 부모 요소를 거쳐야함
Redux : Reduce 보다 광범위적으로 사용됨/ 리액트외 다른 언어에서도 사용 가능
- 리덕스는 리액트의 라이브러리 중 하나
- Props의 불편함을 개선하기 위해 만들어진 개념
- 언제, 어디서든 store에 저장된 state를 가져다 사용할 수 있음
- 단점!! 동기적 타입으로 기능을 수행 : 따라서 복수의 실행함수(리듀서)가 2개이상인 경우 먼저 실행한 실행문이 마쳐야지만 두번째 함수가 실행된다.
- 리덕스를 비동기 타입으로 수행 : redux toolkit : redux middleware
리덕스 기본개념
웹브라우저의 기능 발생
- 액션으로 실행된 결과가 감
- 액션값을 리듀서에 전달 처리 및 실행.
- 값을 스토어에 보냄
- 다시 출력
설치 및 설정
https://ko.redux.js.org/
Redux - 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너. | Redux
자바스크립트 앱을 위한 예측 가능한 상태 컨테이너.
ko.redux.js.org
- 터미널 명령어 입력 npm install redux
- 리액트 리덕스 패키지 입력 (리덕스를 리액트 안에서 보다 쉽게 쓰이게끔 해주는 ) npm install react-redux
https://react-redux.js.org/introduction/getting-started
Getting Started with React Redux | React Redux
Introduction > Getting Started: First steps with React Redux
react-redux.js.org
*리덕스와 리액트 리덕스는 다르다
카운트 예제 짜보기
index.js
import { Provider } from "react-redux";
import store from "./store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
*모든 데이터가 출력되는 공간에 Store를 뿌려준다
-> store.js 파일 생성
store.js (컴포넌트가 아님, 함수임)
import { createStore } from "redux";
import reducer from "./reducer";
let store = createStore(reducer);
export default store;
함수의 실행은 App.js가 보낸(useDispatch 를 통해 보낸) 값을 reducer.js 받아서 실행함
App.js
import { useState } from "react";
import "./App.css";
import { useDispatch, useSelector } from "react-redux";
function App() {
//const [count, setCount] = useState(0);
const dispatch = useDispatch(); //변수에 함수를 할당. (리듀서에 자동으로 값이 감) 변수->함수가됨
const count = useSelector((state) => state.count); //state값을 받아와서 state.count값을 받아옴
const increase = () => {
dispatch({ type: "INCREMENT" }); //리듀서에 값을 보냄
//setCount(count + 1);
};
return (
<div>
<h1>{count}</h1>
<button onClick={increase}>증가!</button>
</div>
);
}
export default App;
또 useSelect 를 통해 reducer 가 실행한 결과값을 받아옴.
reducer.js 생성
리듀서는 2개의 인자값을 반드시 받는다.
- state 변수값 (초기값)
- 실행지침서
//reducer는 반드시 두개의 인자값을 받는다.
//state : 상태변화에 대한 초기값
let initialState = {
count: 0,
}; //초기값을 설정 -> state에 매칭
function reducer(state = initialState, action) {
console.log("action", action);
// if (action.type === "INCREMENT") {
// return { ...state, count: state.count + 1 }; //변하지 않은 요소, 값이 바뀔 요소
// } //무조건 리턴값이 있어야함
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
default: {
return { ...state };
}
}
}
export default reducer;
if 문 / switch 문 사용가능 스위치를 더 많이 씀.
+ 추가기능 부여한 예제
Box.js 컴포넌트 생성. => 증가버튼을 눌렀을떄 박스 컴포넌트에서도 값을 같이 출력하고 싶다.
import React from "react";
import { useSelector } from "react-redux";
// useSelector 를 통해 값을 받아온다
const Box = () => {
let count = useSelector((state) => state.count);
return <div>this is box {count}</div>;
};
export default Box;
+ 감소버튼 추가!
App.js
import { useState } from "react";
import "./App.css";
import { useDispatch, useSelector } from "react-redux";
import Box from "./Components/Box";
function App() {
//const [count, setCount] = useState(0);
const dispatch = useDispatch(); //변수에 함수를 할당. (리듀서에 자동으로 값이 감) 변수->함수가됨
const count = useSelector((state) => state.count); //state값을 받아와서 state.count값을 받아옴
const increase = () => {
dispatch({ type: "INCREMENT" }); //리듀서에 값을 보냄
//setCount(count + 1);
};
const decrease = () => {
dispatch({ type: "DESCREMENT" });
};
return (
<div>
<h1>{count}</h1>
<button onClick={increase}>증가!</button>
<button onClick={decrease}>감소</button>
<Box />
</div>
);
}
export default App;
reducser.js
//reducer는 반드시 두개의 인자값을 받는다.
//state : 상태변화에 대한 초기값
let initialState = {
count: 0,
}; //초기값을 설정 -> state에 매칭
function reducer(state = initialState, action) {
console.log("action", action);
// if (action.type === "INCREMENT") {
// return { ...state, count: state.count + 1 }; //변하지 않은 요소, 값이 바뀔 요소
// } //무조건 리턴값이 있어야함
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DESCREMENT":
return { ...state, count: state.count - 1 };
default: {
return { ...state };
}
}
}
export default reducer;
+ 디스패치 요소 안에 타입말고 다른 요소 들어갈수 있음.
dispatch ( type, payload)
type : 필수인자값
payload: 선택적 *함수의 매개변수 **객체타입으로 값입력
App.js
const increase = () => {
dispatch({ type: "INCREMENT", paylodad: { num: 5 } }); //리듀서에 값을 보냄
//setCount(count + 1);
};
reducer.js
switch (action.type) {
case "INCREMENT":
//return { ...state, count: state.count + 1 };
return { ...state, count: state.count + action.payload.num }; // 5씩 증가하게 됨
num : 5 이기때문에 5씩 증가함.
+ reducer.js 의 초기값 설정도 여러개가 가능하다.
(따라서 리듀서에서 state 변수에 매칭시켜줄 초기값을 설정할때, 따로 변수를 만들어 매칭시켜주는 것.)
app.js
import { useState } from "react";
import "./App.css";
import { useDispatch, useSelector } from "react-redux";
import Box from "./Components/Box";
function App() {
//const [count, setCount] = useState(0);
const dispatch = useDispatch(); //변수에 함수를 할당. (리듀서에 자동으로 값이 감) 변수->함수가됨
const count = useSelector((state) => state.count); //state값을 받아와서 state.count값을 받아옴
const id = useSelector((state) => state.id);
const pw = useSelector((state) => state.pw);
const increase = () => {
dispatch({ type: "INCREMENT", payload: { num: 5 } }); //리듀서에 값을 보냄
//setCount(count + 1);
};
const decrease = () => {
dispatch({ type: "DESCREMENT" });
};
const login = () => {
dispatch({ type: "LOGIN", payload: { id: "kim", pw: "1234" } });
};
return (
<div>
<h1>
{id}, {pw}
</h1>
<h1>{count}</h1>
<button onClick={increase}>증가!</button>
<button onClick={decrease}>감소</button>
<button onClick={login}>로그인</button>
<Box />
</div>
);
}
export default App;
reducer.js
//reducer는 반드시 두개의 인자값을 받는다.
//state : 상태변화에 대한 초기값
let initialState = {
count: 0,
id: "", // 추가
pw: "", //추가
}; //초기값을 설정 -> state에 매칭
function reducer(state = initialState, action) {
console.log("action", action);
// if (action.type === "INCREMENT") {
// return { ...state, count: state.count + 1 }; //변하지 않은 요소, 값이 바뀔 요소
// } //무조건 리턴값이 있어야함
switch (action.type) {
case "INCREMENT":
//return { ...state, count: state.count + 1 };
return { ...state, count: state.count + action.payload.num };
case "DESCREMENT":
return { ...state, count: state.count - 1 };
case "LOGIN":
return { ...state, id: action.payload.id, pw: action.payload.pw };
default: {
return { ...state };
}
}
}
export default reducer;