: 애플리케이션의 상태를 관리하고, .getState(), .dispach(), .subscribe() 같은 메서드를 제공
: React 컴포넌트에 분산되어 있는 상태 객체와 달리 스토어는 하나만 존재합니다. 스토어는 애플리케이션에 상태를 제공하며 상태가 업데이트 되면 뷰(UI)가 다시 그려진다.
: "상태 변경을 설명하는 정보"를 스토어로 보내는 JavaScript 객체로 Redux에 알려(dispatch) 변화를 이끌어낸다.
: store 안에 들어있는 상태를 조회
: getState를 통해 state값에 접근
: state값을 참조하여 ui를 생성
: state값을 직접 변경해서는 안된다.
-> {...state}와 같이 새로운 객체를 생성!
: dispatch는 reducer를 호출하여 state 값을 바꾼다.
: reducer에 (state, action)라는 두가지 값을 전달
: 현재의 store의 state값 & dispatch를 통해 보낸 값(action)
: 애플리케이션 상태를 교체하는 함수
: dispatch에 의해 reducer함수 호출
: state를 입력값으로 받고 action를 참조하여 새로운 state값을 리턴
: reducer에서 return해주는 값이 state의 새로운 값이 된다.
: 상태 변경을 구독(subscribe, 감지) 하여, 상태가 업데이트 되면 등록된 리스너(listener)를 실행
: render함수를 subscribe에 등록하여 state값이 바꿀 때마다 render함수가 호출되어 ui가 변경된다.
리덕스 스토어의 상태를 조회하는 Hook
useSelector를 사용해서 리덕스 스토어의 상태를 조회 할 때, 만약 상태가 바뀌지 않았으면 리렌더링하지 않는다.
아래와 같이 작성한다면 매번 렌더링 될 때마다 새로운 객체를 만드는 것이기 때문에, 불필요한 렌더링이 발생할 수 있다.
const { subscribers, view } = useSelector(state => ({
subscribers: state.subscribers,
view state.view
}));
const state = useSelector((state) => state.itemReducer);
const { cartItems, items } = state;
이를 최적화하기 위한 방법은 두가지가 있다.
const number = useSelector(state => state.counter.number);
const diff = useSelector(state => state.counter.diff);
const { number, diff } = useSelector(
state => ({
number: state.counter.number,
diff: state.counter.diff
}),
shallowEqual
);
리덕스 스토어의 dispatch 를 함수에서 사용 할 수 있게 해주는 Hook
const dispatch = useDispatch();
const dispatch = useDispatch();
return(
<button onClick={() => dispatch(addSubscriber())}>UPUP</button>
)
export const ADD_NUMBER = 'ADD_NUMBER';
export const ADD_NUMBER_LATER = 'ADD_NUMBER_LATER';
import { ADD_NUMBER } from './type';
import { ADD_NUMBER_LATER } from './type';
export const addNumber = () => {
return {
type: ADD_NUMBER,
};
};
export const addNumberLater = () => {
return (dispatch, getState) => {
setTimeout(() => dispatch(addLater()), 1000);
};
};
const addLater = () => {
return {
type: ADD_NUMBER_LATER,
};
};
import { ADD_NUMBER, ADD_NUMBER_LATER } from './type';
const initialState = {
count: 330,
};
const addNumberReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_NUMBER:
return { ...state, count: state.count + 1 };
//! default를 꼭 설정해줘야 한다!!
case ADD_NUMBER_LATER:
return { ...state, count: state.count + 3 };
default:
return state;
}
};
export default addNumberReducer;
import addMessageReducer from './message/reducer';
import addNumberReducer from './number/reducer';
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
number: addNumberReducer,
message: addMessageReducer,
});
export default rootReducer;
import { createStore, applyMiddleware } from 'redux';
import addNumberReducer from './number/reducer';
import rootReducer from './rootReducer';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
const middeWare = [thunk];
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(...middeWare))
);
export default store;
import './App.css';
import Message from './components/Message';
import Number from './components/Number';
import { Provider } from 'react-redux';
import store from './redux/store';
function App() {
return (
<Provider store={store}>
<Number />
<Message />
</Provider>
);
}
export default App;
styled component, redux 등 같이 사용했을
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';
import GlobalStyle from './styled/globalStyled';
import { ThemeProvider } from 'styled-components';
import theme from './styled/theme';
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<ThemeProvider theme={theme}>
<GlobalStyle />
<App />
</ThemeProvider>
</Provider>
</React.StrictMode>,
document.getElementById('root')
);