- useState의 불편함
- 어떤 컴포넌트에서 생성한 state를 다른 컴포넌트로 보고자 할 때 우리는 어떻게 했었나요? Props를 통해서 부모 컴포넌트에서 자식 컴포넌트로 그 값을 보내주었습니다. 근데 Props로 State를 공유하는 방법에는 불편한 점이 있습니다.
- 컴포넌트에서 컴포넌트로 State를 보내기위해서는 반드시 부-모 관계가 되어야 한다.
- 조부모 컴포넌트에서 손자 컴포넌트로 값을 보내고자 할때도 반드시 부모 컴포넌트를 거쳐야만 한다. 즉, 정작 부모컴포넌트에서는 그 값이 필요가 없어도 단순히 손자 컴포넌트에게 전달하기 위해 불필요하게 거쳐야만 하는 것을 의미한다. (조부모 → 부모 → 손자)
- 자식 컴포넌트에서 부모 컴포넌트로 값을 보낼 수 없다.
Redux - 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너. | Redux
자바스크립트 앱을 위한 예측 가능한 상태 컨테이너.
ko.redux.js.org
리덕스란,
우리가 위에서 말한 “중앙 state 관리소”를 사용할 수 있게 도와주는 패키지(라이브러리) 입니다. “중앙 state 관리소" 를 통해서 State를 관리한다는 아이디어는 굉장히 좋으나, 우리가 그것을 직접 구현하기는 아직 어려우니까요. 패키지(라이브러리)의 도움을 받아 그것을 구현해보고자 합니다.
프론트엔드 개발자들은 “리덕스”를 전역 상태관리 라이브러리 라고 많이 표현합니다. 전역 상태, 즉 Global State를 의미하고 그것을 관리하게 도와주는 라이브러리 (패키지) 이기 때문입니다.
- 리덕스는 전역상태 관리 라이브러리이다.
- 리덕스는 useState를 통해 상태를 관리했을 때 발생하는 불편함을 일부 해소시켜준다.
- 리덕스는 중앙 State 관리소를 가지고 있으며, 모든 State는 이곳에서 생성된다.
- useState로 생성한 State는 Local State이고, 리덕스에서 생성한 State는 Global State이다.
코딩 애플님의 설명
이영상 한번 보고 단번에 이해했다.
리덕스 흐름도
Redux 기반, Part 2: Concepts and Data Flow | Redux
The official Redux 기반 튜토리얼: learn key Redux terms and how data flows in a Redux app
ko.redux.js.org
리덕스 공식문서에서 긁어 왔다...
- Redux의 의도는 세 가지 원칙으로 요약될 수 있습니다.
- 글로벌 앱 상태는 단일 스토어에 보관됩니다.
- 스토어 상태는 앱의 나머지 부분에 대해 읽기 전용입니다.
- 리듀서 함수는 동작에 대한 응답으로 상태를 업데이트하는 데 사용됩니다.
- Redux는 "단방향 데이터 흐름" 앱 구조를 사용합니다.
- State는 특정 시점의 앱 상태를 설명하고 UI는 해당 상태를 기반으로 렌더링됩니다.
- 앱에서 문제가 발생하면:
- UI가 작업을 전달합니다.
- 상점은 감속기를 실행하고 상태는 발생한 일에 따라 업데이트됩니다.
- 상점은 상태가 변경되었음을 UI에 알립니다.
- UI는 새 상태를 기반으로 다시 렌더링됩니다.
어떤분 블로그 글을 가져왔다.
리덕스 흐름 이해하기
리덕스는 가장 많이 사용하는 리액트 상태 관리 라이브러리입니다. 리덕스를 사용하면 컴포넌트의 상태 업데이트 관련 로직을 다른 파일로 분리시켜서 더욱 효율적으로 관리할 수 있다. 또한,
velog.io
리덕스의 핵심 요소 :
- Action:
State가 변하는것. “무엇이 일어날지” - Reducer:
변화를 일으키는, 즉 데이터(state)를 수정하는 함수. action을 통해 어떠한 행동을 정의했다면, 그 결과 어플리케이션의 상태가 어떻게 바뀌는지는 특정하게 되는 함수이다. - Store:
action과 action에 따라 상태를 수정하는 reducer를 저장하는 어플리케이션에 있는 단 하나의 객체. 스토어는 State 를 수시로 확인해 View 한테 변경된 사항을 알려주는 역할을 한다. - Dispatch:
스토어의 내장 함수 중 하나로 리듀서에게 Action 을 발생하라고 시키는 것 store에서 reducer함수를 실행시켜 state를 업데이트한다. - Subscribe:
액션이 디스패치 될 때 마다 전달해준 함수를 호출한다. - Middleware: 액션을 디스패치 했을때 리듀서에서 이를 처리하기에 앞서 사전에 지정된 작업들을 실행한다.
thunk 와 saga 가 대표.
리덕스를 써보기 위해 설치를 진행한다
yarn add redux react-redux
아래와 같은 의미
yarn add redux
yarn add react-redux
- src 폴더 안에 redux 폴더를 생성
- redux 폴더 안에 config, modules 폴더를 생성
- config 폴더 안에 configStore.js파일을 생성
각각의 폴더와 파일의 역할
- redux : 리덕스와 관련된 코드를 모두 모아 놓을 폴더
- config : 리덕스 설정과 관련된 파일들을 놓을 폴더
- configStore : “중앙 state 관리소" 인 Store를 만드는 설정 코드들이 있는 파일
- modules : 리듀서를 모아놓을 폴더
index.js
import store from "./redux/config/configStore";
import { Provider } from "react-redux";
<Provider store={store}>
<App />
</Provider>
Provider 리덕스의 내장 컴포넌트이다.
store의 범위를 정한다
속성값으로 반드시 store를 넣어줘야한다.
configStore.js
import { createStore } from "redux";
import { combineReducers } from "redux";
// 새롭게 추가한 부분
import counter from "../modules/counter";
const rootReducer = combineReducers({
counter: counter, // <-- 새롭게 추가한 부분
});
const store = createStore(rootReducer);
export default store;
리듀서를 담고 스토어를 만드는 파일이다.
combineReducers 안에 객체의 요소로 만든 리듀서를 넣어주면
스토어객체에서 요소로 리듀서에 접근할수있다.
createStore대신 요즘은 toolkit을 사용하는 것같다
익숙해지면 그것도 한번 써봐야겠다.
(Redux에서도 createStore는 그만쓰라고 하고있기도...)
counter.js
// 추가된 코드 👇 - 액션 value를 상수들로 만들어 줍니다. 보통 이렇게 한곳에 모여있습니다.
const PLUS_ONE = "PLUS_ONE";
const MINUS_ONE = "MINUS_ONE";
const ADD_NUMBER = "ADD_NUMBER";
// 추가된 코드 👇 - Action Creator를 만들어 줍니다.
export const plusOne = () => {
return {
type: PLUS_ONE,
};
};
export const minusOne = () => {
return {
type: MINUS_ONE,
};
};
export const addNumber = (payload) => {
return {
type: ADD_NUMBER,
payload: payload
};
};
// 초기 상태값
const initialState = {
number: 0,
};
// 리듀서
const counter = (state = initialState, action) => {
console.log(action); // 여기에 console.log(action) 추가
switch (action.type) {
case PLUS_ONE:
return { number: state.number + 1 };
case MINUS_ONE:
return { number: state.number - 1 };
case ADD_NUMBER:
return { number: state.number + action.payload };
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
리듀서counter 파일이다.
유저로부터 action을 받아 처리하고 상태를 반환한다.
App.js
import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux"; // import 해주세요.
import { addNumber, minusOne, plusOne } from "./redux/modules/counter";
import styled from "styled-components";
const App = () => {
const globalNumber = useSelector((state) => state.counter.number); //state선언
const dispatch = useDispatch(); // dispatch 생성
const [number, setNumber] = useState(0);
const onChangeHandler = (e) => {
const { value } = e.target;
setNumber(Number(value));
}
const onCLickAddNumberHandler = () => {
dispatch(addNumber(number));
}
const Stdiv = styled.div`
text-align : center;
background-color : ${(props) => props.backgroundColor};
`;
return (
<>
<Stdiv backgroundColor="orange">
{globalNumber}
<input type="number" onChange={onChangeHandler} />
<button
// 이벤트 핸들러 추가
onClick={onCLickAddNumberHandler}
>
addNumber
</button>
<button
// 이벤트 핸들러 추가
onClick={() => {
// 마우스를 클릭했을 때 dispatch가 실행되고, ()안에 있는 액션객체가 리듀서로 전달된다.
dispatch(plusOne());
}}
>
+ 1
</button>
<button
// 이벤트 핸들러 추가
onClick={() => {
// 마우스를 클릭했을 때 dispatch가 실행되고, ()안에 있는 액션객체가 리듀서로 전달된다.
dispatch(minusOne());
}}
>
- 1
</button>
</Stdiv>
</>
)
}
export default App;
globalNumber라는 store에서 상태값을 받을 변수를 선언하고
uesDispatch를 이용해 store의 상태값을 변경시킬 dispatch를 선언하여 처리했다.
학습자료 따라 치는건데 어려웠다...
흐름을 이해했으니 계속 써보면서 익숙해지는방법 밖에...
'React' 카테고리의 다른 글
React-router-dom 사용하기 (0) | 2022.10.07 |
---|---|
React-redux 1주차 미션에 적용해보기 (1) | 2022.10.07 |
CSS-in-Js사용법 쓰는 이유 (0) | 2022.10.06 |
React 생성 기본 설치 할 것들 (0) | 2022.10.05 |
React useState 이해하기 (1) | 2022.10.01 |