react-redux(2022 개정판) 을 듣고 정리한 내용입니다.
react-redux
란 redux를 react에서 쉽게 사용할 수 있도록 돕는 도구이다.
컴포넌트 간에 데이터를 주고 받을 때 사용하는 것이 props
이다.
import React, { useState } from 'react';
import './style.css';
export default function App() {
const [number, setNumber] = useState(1);
return (
<div id="container">
<h1>Root : {number}</h1>
<div id="grid">
<Left1 number={number}></Left1>
</div>
</div>
);
}
function Left1(props) {
return (
<div>
<h1>Left1 : {props.number}</h1>
<Left2 number={props.number}></Left2>
</div>
);
}
function Left2(props) {
return (
<div>
<h1>Left2 : {props.number}</h1>
<Left3 number={props.number}></Left3>
</div>
);
}
function Left3(props) {
return (
<div>
<h1>Left3 : {props.number}</h1>
</div>
);
}
위 예시는 3개의 컨테이너가 중첩되어있다.
실행을 하면 다음과 같은 화면이 나온다.
Root
에서 Left3
까지 number
를 전달하기 위해선 중첩된 컨테이너에 모두 props
전달해 주어야함 하위 컴포넌트까지 데이터를 전달할 수 있게 된다.
중첩된 컴포넌트가 수십, 수백개가 되는 경우엔 어떻게 해야할까?
수십, 수백개의 컴포넌트를 모두 props
로 연결하지 않고도 컴포넌트에 데이터를 전달하는 방법을 알아보자.
npm install redux react-redux
위 명령어를 이용하여 redux
와 react-redux
를 설치하자.
store
는 데이터를 저장하고 있는 공간이다.
이 공간을 만들기 위해 redux
에서 createStore
를 만들어 주자.
store
는 불변상태로 저장되어야 하므로 const
로 사용해 상수로서 선언하였다.
import { createStore } from 'redux';
const store = createStore(reducer);
reducer
는 데이터의 상태 변화를 전달해준다.
store
와 연결하여 변경된 상태를 저장한다.
reducer
는 현재상태와, 어떻게 바꿀 것인지 요청을 받는 두개의 파라메터를 인자로 받는다.
function reducer(currentState, action) {
// 현재 상태가 정의 되지 않았다면
// 기본 상태값을 리턴
if (currentState === undefined) {
return {
number: 1,
};
}
currentState
가 정의되어있지 않는 경우에 기본값을 현재 상태로 지정해주었다.
import { Provider, useSelector, useDispatch, connect } from 'react-redux';
Provider
는react-redux
에서 임포트해서 사용하는 4가지 항목 중 하나로써, 상태 데이터를 어떤 컴포넌트에게 전달할지 지정해주는 컴포넌트이다.
export default function App() {
return (
<div id="container">
<h1>Root </h1>
<div id="grid">
{/* Provider는 store이라는 props를 반드시 전달해주어야한다. */}
<Provider store={store}>
<Left1></Left1>
</Provider>
</div>
</div>
);
}
Left1
컴포넌트를 Provider
로 감싼 후, store
를 전달해 주자.
reducer
의 currentState
가 정의되지 않았으므로 기본 값인 1이 number
에 저장된다.
useSelector
는 상태를 전달 받고 싶을 곳에서 사용한다.
props
를 통해 Left1
, Left2
를 거치지 않고 직접 Left3
에게 직접 전달해 줄 것이므로 다음과 같이 Left3
컴포넌트를 수정하자.
function Left3(props) {
// number 값을 직접 전달받고 싶을때
// useSelector는 함수를 인자로 받는다.
const number = useSelector((state) => state.number);
return (
<div>
<h1>Left3 : {number} </h1>
</div>
);
}
useDispatch
는 상태 값을 변경할 때 사용한다.
Left3
에 버튼을 만들고, 버튼을 클릭할때마다 number
가 하나씩 증가하도록 해보자.
function Left3(props) {
// number 값을 무선으로 전달받고 싶을때
// useSelector는 함수를 인자로 받는다.
const number = useSelector((state) => state.number);
// 상태값 변경
const dispatch = useDispatch();
return (
<div>
<h1>Left3 : {number} </h1>
<input
type="button"
value="+"
onClick={() => {
dispatch({ type: 'PLUS' });
}}
></input>
</div>
);
}
onClick
이 이루어 질때마다 dispatch
는 store
의 reducer
에게 action
을 전달해 준다.
reducer
함수를 수정해보자.
function reducer(currentState, action) {
// 현재 상태가 정의 되지 않았다면
// 기본 상태값을 리턴
if (currentState === undefined) {
return {
number: 1,
};
}
// state 의 변화를 불변하게 유지하기 위해 복제
// 복제본을 수정
const newState = { ...currentState };
if (action.type === 'PLUS') {
newState.number++;
}
return newState;
}
상태를 변경하기 위해서는 깊은 복사가 이루어져야한다.
현재 상태를 복제하고 복제본을 수정하여 리턴하면 상태가 변경된다.
import React, { useState } from 'react';
import './style.css';
import { createStore } from 'redux';
// 4인방
// 컴포넌트, 어떤스테이트를 사용할지 선택할때, 스테이트 값을 변경
import { Provider, useSelector, useDispatch, connect } from 'react-redux';
function reducer(currentState, action) {
// 현재 상태가 정의 되지 않았다면
// 기본 상태값을 리턴
if (currentState === undefined) {
return {
number: 1,
};
}
// state 의 변화를 불변하게 유지하기 위해 복제
// 복제본을 수정
const newState = { ...currentState };
if (action.type === 'PLUS') {
newState.number++;
}
return newState;
}
const store = createStore(reducer);
export default function App() {
return (
<div id="container">
<h1>Root </h1>
<div id="grid">
{/* Provider는 store이라는 props를 반드시 전달해주어야한다. */}
<Provider store={store}>
<Left1></Left1>
</Provider>
</div>
</div>
);
}
function Left1(props) {
return (
<div>
<h1>Left1 : </h1>
<Left2></Left2>
</div>
);
}
function Left2(props) {
return (
<div>
<h1>Left2 : </h1>
<Left3></Left3>
</div>
);
}
function Left3(props) {
// number 값을 무선으로 전달받고 싶을때
// useSelector는 함수를 인자로 받는다.
const number = useSelector((state) => state.number);
const dispatch = useDispatch();
return (
<div>
<h1>Left3 : {number} </h1>
<input
type="button"
value="+"
onClick={() => {
dispatch({ type: 'PLUS' });
}}
></input>
</div>
);
}