리덕스는 리엑트와는 상관없는 도구, 리덕트를 사용해 리엑트의 생산성을 높일 수 있음
리덕스를 쓰는 이유를 알기 위해서 순수 리엑트만으로 앱을 만들어 보고, 그 안에서 생긴 불편함을 리덕트를 사용해서 극복하는 과정을 거치겠음
stackblitz를 활용
left 1,2,3 컴포넌트 만듦.
기본값이 1인 넘버스테이트를 정의
const [number, setNumber] = useState(1);
최상위에 있는 넘버 스테이트를 말단의 left3에게 전달하려면
<Left1 number={number}></Left1>
...
<h1>Left1: {props.number}</h1>
h2와 h3에도 반복
이런 과정을 여러번 거쳐야함.
일단 right3에 버튼을 만들고 이벤트를 걺
<input type="button" value="+" onClick={()=>{props.Increase();}}></input>
<Right3 onIncrease={() => {props.onIncrease();}}></Right3>를 반복
최상위 칸에는 setNumber를
<Right1 onIncrease={() => {setNumber(number + 1);}}></Right1>
Root와 버튼 사이의 컴포넌트들에 하나하나 코드를 넣어줘야함. 마치 prop을 이용해서 유선으로 연결되어있는 것과 다를바 없음.
리덕스를 사용하면 블루투스를 사용한 것과 비슷한 효과
독립적인 도구인 리엑트와 리덕스를 연결하는 도구 react-redux
//redux와 react-redux을 같이 설치
npm install redux react-redux
import React, { useState } from 'react';
import './style.css';
import { createStore } from 'redux'; //제일 먼저 스토어 생성
import { Provider, useSelector, useDispatch, connect } from 'react-redux';
//리엑트 리덕스의 4인방 Provider:컴포넌트, useSelector:어떤 스테이트 값을 쓸지 선택하는 것 ,useDispatch: 스테이트 값을 변경할 때 사용, connect: 어렵고 재사용성을 할때만 사용됨
function reducer(currentState, action) { //리뷰서는 스토어 안에 있는 스테이트를 어떻게 바꿀지 결정함. 따라서 두개의 파라미터를 가짐. 첫번재 파라미터는 현재의 스테이트값, 둘째 파라미터는 어떻게 받을지를 의미하는 액션
if (currentState === undefined) { //숫자가 정의되지 않았을 경우 1을 기본 스테이트값으로 하고 리턴
return {
number: 1,
};
}
const newState = { ...currentState }; //새로운 스테이트를 받는데 과거의 스테이트를 복제
if (action.type === 'PLUS') {
newState.number++;
}
return newState; //11줄로 변화시킨 스테이트를 리턴한다
}
const store = createStore(reducer);
export default function App() {
return (
<div id="container">
<h1>Root</h1> //이제 루트에 있는 데이터는 필요 없으므로 number와 setNumber을 지워버림
<div id="grid">
<Provider store={store}> //프로바이더의 프롭중에 스토어를 반드시 정의해야함 //18줄의 스토어가 {괄호}안으로 들어감
<Left1></Left1>
<Right1></Right1>
</Provider>
</div>
</div>
);
}
function Left1(props) {
return (
<div>
<h1>Left1 : {props.number}</h1>
<Left2 number={props.number}></Left2>
</div>
);
}
function Left2(props) {
console.log('2');
return (
<div>
<h1>Left2 : {props.number}</h1>
<Left3 number={props.number}></Left3>
</div>
);
}
function Left3(props) {
console.log('3');
const number = useSelector((state) => state.number);
return (
<div>
<h1>
Left3 : {number}
{props.number}
</h1>
</div>
);
}
function Right1(props) {
return (
<div>
<h1>Right1</h1>
<Right2
onIncrease={() => {
props.onIncrease();
}}
></Right2>
</div>
);
}
function Right2(props) {
return (
<div>
<h1>Right2</h1>
<Right3
onIncrease={() => {
props.onIncrease();
}}
></Right3>
</div>
);
}
function Right3(props) {
const dispatch = useDispatch();
return (
<div>
<h1>Right3</h1>
<input
type="button"
value="+"
onClick={() => {
dispatch({ type: 'PLUS' });
}}
></input>
</div>
);
}
//넘버 값을 무선으로 연결하려면
function f(state){
return state.number;
}
function Left3(props) {
const number = useSelector(f); //넘버값을 무선으로 연결하기 위해서 함수를 인자로 받는 useSelector를 사용,
return (
<div>
<h1>Left3 : </h1>
</div>
);
}
//위의 f 함수를 간단하게 쓰면
function Left3(props) {
const number = useSelector((state) => state.number);
return (
<div>
<h1>
Left3 : {number} //스토어에 저장된 넘버스테이트와 말단 Left3컴포넌트를 무선으로 연결한 것
</h1>
</div>
);
}
버튼을 누르면 숫자가 바뀌게 하기 위해서 디스패치를 활용함.