7일차(6.1~6.5)
01. 리덕스에서 사용되는 키워드 숙지하기
액션 (Action)
- 상태에 어떠한 변화가 필요하게 될 때 액션이란 것을 발생시킨다
- 하나의 객체로 표현된다
type
필드는 필수, 그 외의 값들은 마음대로 설정할 수 있다
{
type: "ADD_TODO", // 액션의 이름(필수)
data: { // 상태 변화 시 필요한 값
id: 0,
text: "리덕스 배우기"
}
}
액션 생성 함수 (Action Creator)
- 액션을 만드는 함수
- 파라미터를 받아와서 액션 객체 형태로 만든다
- 단지 컴포넌트에서 더욱 간편하게 액션을 발생시키기 위해 생성
- 보통 함수 앞에
export
키워드를 붙여서 다른 파일에서 불러와서 사용한다
export function addTodo(data) {
return {
type: 'ADD_TODO', // 함수 이름과 같은 이름
data, // 전달된 파라미터 값
}
}
리듀서 (Reducer)
- 상태 변화로 로직을 작성해둔 함수
- 상태와, 액션 객체 두개의 파라미터를 받아온다
- 현재의 상태와 전달 받은 액션을 참고하여 새로운 상태를 만들어서 반환한다
- default: 부분에 기존 상태를 그대로 반환하도록 작성해야한다
- 여러 개의 리듀서(서브 리듀서)를 만들고 이를 합쳐서 루트 리듀서를 만들 수 있다
function counter(state, action) {
switch (action.type) {
case 'INCREASE':
return state + 1
case 'DECREASE':
return state - 1
default:
return state
}
}
스토어 (Store)
- 한 애플리케이션당 하나의 스토어를 만들 수 있다
- 상태와, 리듀서, 몇가지 내장 함수들이 포함된다.
디스패치 (dispatch)
- 스토어의 내장함수 중 하나
- 액션을 발생시키는 함수
- 액션 객체를 파라미터로 전달
- 호출 시 스토어는 리듀서 함수를 실행시켜서 해당 액션을 처리하는 로직이 있다면 액션을 참고하여 새로운 상태를 만들어준다
02. 리덕스의 3가지 규칙
1. 하나의 애플리케이션 안에는 하나의 스토어가 있다
2. 상태는 읽기 전용이다
- 기존의 상태는 건드리지 않고 새로운 상태를 생성하여 업데이트 해주면,
나중에 개발자 도구를 통해서 뒤로 돌릴 수도 있고 다시 앞으로 돌릴 수 있다 - 불변성을 유지해야하는 이유
- 객체의 변화를 감지 할 때 shallow equality 검사를 해, 겉핥기 식으로 비교를 하기 때문
- 이로써 좋은 성능을 유지할 수 있다
안쪽까지 검사를 안하기 때문에 겉은 같고 내부만 바꿔봤자 변한지 모른다
그래서 겉까지 싹다 바꿔줘야 함
3. 변화를 일으키는 함수, 리듀서는 순수한 함수여야 한다
- 리듀서 함수는 이전 상태와, 액션 객체를 파라미터로 받는다
- 이전의 상태는 절대로 건드리지 않고, 변화를 일으킨 새로운 상태 객체를 만들어서 반환한다
- 똑같은 파라미터로 호출된 리듀서 함수는 언제나 똑같은 결과값을 반환해야만 한다
→ new Date(), 랜덤 숫자 생성, 네트워크 요청 등 실행 시마다 다른 결과를 내는 로직은 사용하면 안된다
03. 리덕스 사용할 준비하기
코드 작성
04. 리덕스 모듈 만들기
리덕스 모듈 - Ducks 패턴
- 액션 타입
- 액션 생성함수
- 리듀서
이 모두 포함된 js파일(각각 다른 파일에 저장 할 수도 있다)
1. 리듀서 생성하기
/* **액션 타입 만들기** */
액션의 이름에 접두사를 넣어야 중복을 방지할 수 있다
/* **액션 생성함수 만들기** */
export사용해 내보내준다
/* **초기 상태 선언** */
/* **리듀서 선언** */
export default로 내보낸다
여러 리듀서 합치기
- 한 프로젝트에 여러개의 리듀서가 있을때는 이를 한 리듀서로 합쳐서 사용한고 합쳐진 리듀서를 루트 리듀서라고 부른다
- 리덕스에 내장되어있는
[combineReducers](https://redux.js.org/api/combinereducers)
라는 함수를 사용 - index.js파일에서 합쳐준다
import { combineReducers } from 'redux'
import counter from './counter'
import todos from './todos'
const rootReducer = combineReducers({
counter,
todos,
})
export default rootReducer
2. 스토어 만들기
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import * as serviceWorker from './serviceWorker'
import { createStore } from 'redux'
import rootReducer from './modules'
const store = createStore(rootReducer) // 스토어를 만듭니다
console.log(store.getState()) // 스토어의 상태 확인
ReactDOM.render(<App />, document.getElementById('root'))
serviceWorker.unregister()
3. 리액트 프로젝트에 리덕스 적용하기
리액트 프로젝트에 리덕스를 적용 할 때, react-redux라는 라이브러리의 Provider컴포넌트를 사용
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import * as serviceWorker from './serviceWorker'
import { createStore } from 'redux'
import rootReducer from './modules'
import { Provider } from 'react-redux' // Provier컴포넌트를 꺼내옴
const store = createStore(rootReducer)
ReactDOM.render(
<Provider store={store}>
{' '}
// App에 감싼 후 store를 전달해주면 어떤 컴포넌트던지 스토어에 접근할 수 있다
<App />
</Provider>,
document.getElementById('root')
)
serviceWorker.unregister()
05. 카운터 구현하기
프리젠테이셔널 컴포넌트
리덕스 스토어에 직접적으로 접근하지 않고 필요한 값 또는 함수를 props으로만 받아와서 사용하는 컴포넌트
- UI를 선언하는 것에 집중
- 필요한 값들이나 함수는 props 로 받아와서 사용
컨테이너 컴포넌트
리덕스 스토어의 상태를 조회하거나, 액션을 디스패치 할 수 있는 컴포넌트를 의미
- HTML 태그들을 사용하지 않는다
- 다른 프리젠테이셔널 컴포넌트들을 불러와서 사용한다
- page같은 느낌
06. 리덕스 개발자도구 적용하기
- 현재 스토어의 상태 조회
- 어떤 액션들이 디스패치 되었는지 확인 가능
- 액션에 따라 상태가 어떻게 변화했는지 확인 가능
- 액션을 직접 디스패치 할 수도 있다
yarn add redux-devtools-extension
index.js
import { composeWithDevTools } from 'redux-devtools-extension'
07. 할 일 목록 구현하기
- TodosContainer → redux에서 값 받아옴
- Todos
- TodoList
- TodoItem
- TodoList
props로 쭉쭉 내려가면서 사용
08. useSelector 최적화
객체로 만들어주게되면 렌더링될 때마다 새로운 객체를 만드는 것이기 때문에 내부의 요소(상태)가 바뀌었는지 아닌지 확인을 할 수 없어서 낭비 렌더링이 이루어진다
const { number, diff } = useSelector(state => ({
number: state.counter.number,
diff: state.counter.diff
}));
최적화하기 위한 방법
- 객체로 만들지 말고 각각 만들어준다
const number = useSelector(state => state.counter.number);
const diff = useSelector(state => state.counter.diff);
- react-redux의
shallowEqual
함수를useSelector
의 두번째 인자로 전달해준다
import React from 'react';
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
import Counter from '../components/Counter';
import { increase, decrease, setDiff } from '../modules/counter';
function CounterContainer() {
const { number, diff } = useSelector(
state => ({
number: state.counter.number,
diff: state.counter.diff
}),
shallowEqual // 객체 안의 가장 겉에 있는 값들을 모두 비교해준다
);
(...)
Author And Source
이 문제에 관하여(7일차(6.1~6.5)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yooon26/7일차6.16.5저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)