์คํ ์ด ๊ฐ์ด ํ์ํ ์ปดํฌ๋ํธ๋ ์คํ ์ด๋ฅผ ๊ตฌ๋
ํ๋ค
๊ตฌ์ฑ์์ | ์ญํ |
---|---|
store | ์ํ๊ฐ ์ ์ฅ์. ์ดํ๋ฆฌ์ผ์ด์ ์ ์ํ ๊ฐ์ ๊ฐ๊ณ ์๊ณ , ๊ด๋ฆฌํ๋ค |
action | ์ํ์ ๋ณํ ๋ฅผ ์ผ์ผ์ผ์ผํ ๋ ์ก์
์ ์คํ ์ด์ ์ ๋ฌ ๊ฐ์ฒด ํํ ๋ก ๋์ด์์ผ๋ฉฐ, ์ํ๋ฅผ ๋ณํ์ํฌ ๋ ์ด ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํด ๋ณํ๋ฅผ ์ผ์ผํด |
Action Creator | ์ก์ ์์ฑ ํจ์. ์ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ธฐ ์ํ ํจ์ |
dispatch | action์ store์ ์ ๋ฌํ๋ ๊ฒ |
reducer | ์ก์
๊ฐ์ฒด๋ฅผ ์ ๋ฌ๋ฐ์ ์์ฒญ์ ์๋ณ(type)ํด ์ํ๋ฅผ ๋ฐ๊พธ๋ ํจ์ (์ด์ ์ํ, ์ก์ )=>๋ค์์ํ |
state | ๋ฆฌ๋์ค์์ ์ ์ฅํ๊ณ ์๋ ์ํ๊ฐ(๋ฐ์ดํฐ), ๋์ ๋๋ฆฌ ํํ |
๋ถ๋ณ์ฑ
์ ์ ์งํด์ฃผ๊ธฐ ์ํจ. action์ ํตํด ๋ณ๊ฒฝ์์ผ์ผ ๋ค๋ฅธ ์ปดํฌ๋ํธ๋ค์ด state๊ฐ ๋ณ๊ฒฝ๋๊ฒ์ ์ ์ ์์$ yarn add redux react-redux
// redux/modules/bucket.js
// Actions
const LOAD = 'bucket/LOAD';
const CREATE = 'bucket/CREATE';
const initailState = {
list: ['์ํ๊ด ๊ฐ๊ธฐ', '๋งค์ผ ์ฑ
์ฝ๊ธฐ', '์์ ๋ฐฐ์ฐ๊ธฐ']
};
// Action Creators
export const loadBucket = (bucket) => {
return { type: LOAD, bucket };
};
export const loadBucket = (bucket) => {
return { type: CREATE, bucket };
};
// Reducer
export default function reducer(state = {}, action = {}) {
switch (action.type) {
case 'bucket/LOAD': {
return state;
}
case 'bucket/CREATE': {
const new_bucket_list = [...state.list, action.bucket];
return { list: new_bucket_list };
}
default:
return state;
}
}
//redux/configStore.js
import { createStore, combineRedcers, combineReducers } from 'redux';
import bucket from './modules/bucket';
import { createBroswerHistory } from 'history';
export const history = createBroswerHistory();
const rootReducer = combineReducers({ bucket });
const store = createStore(rootReducer);
export default store;
// index.js
...
import { Provider } from 'react-redux';
import store from './redux/configStore';
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
//App.js
import React from 'react';
import logo from './logo.svg';
// BucketList ์ปดํฌ๋ํธ๋ฅผ import ํด์ต๋๋ค.
// import [์ปดํฌ๋ํธ ๋ช
] from [์ปดํฌ๋ํธ๊ฐ ์๋ ํ์ผ๊ฒฝ๋ก];
...
import { connect } from 'react-redux';
import { createBucket, loadBucket } from './redux/modules/bucket';
const mapStateToProps = (state) => {
return { bucket_list: state.bucket.list };
};
const mapDispatchToProps = (dispatch) => {
return {
load: () => {
dispatch(loadBucket());
},
create: (bucket) => {
dispatch(createBucket(bucket));
}
};
};
// ํด๋์คํ ์ปดํฌ๋ํธ๋ ์ด๋ ๊ฒ ์๊ฒผ์ต๋๋ค!
class App extends React.Component {
constructor(props) {
super(props);
// App ์ปดํฌ๋ํธ์ state๋ฅผ ์ ์ํด์ค๋๋ค.
this.state = {
list: ['์ํ๊ด ๊ฐ๊ธฐ', '๋งค์ผ ์ฑ
์ฝ๊ธฐ', '์์ ๋ฐฐ์ฐ๊ธฐ']
};
}
// ๋๋ ํจ์ ์์ ๋ฆฌ์กํธ ์๋ฆฌ๋จผํธ๋ฅผ ๋ฃ์ด์ค๋๋ค!
render() {
return (
<div className="App">
<Container>
...
</Container>
</div>
);
}
}
...
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(App));
// ์ปดํฌ๋ํธ onclick์ด๋ฒคํธ
addBucketList = () => {
const new_item = this.text.current.value;
this.props.create(new_item);
};
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { deleteBucket } from './redux/modules/bucket';
const Detail = (props) => {
const bucket_list = useSelector((state) => state.bucket.list);
const dispatch = useDispatch();
const bucketIdx = parseInt(props.match.params.index);
const onDeleteBucket = () => {
dispatch(deleteBucket(bucketIdx));
props.history.push('/');
};
return (
<div>
<h1>{bucket_list[bucketIdx]}</h1>
<button onClick={onDeleteBucket}>์ญ์ ํ๊ธฐ</button>
</div>
);
};
export default Detail;
$ yarn add @reduxjs/toolkit
// configStore.js
import { createStore, applyMiddleware, combineReducers } from 'redux';
import schedule from './modules/schedule';
//import { createBrowserHistory } from 'history';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
//export const history = createBrowserHistory();
const middlewares = [thunk];
const enhancer = applyMiddleware(...middlewares);
const rootReducer = combineReducers({ schedule });
const store = createStore(rootReducer, composeWithDevTools(enhancer));
export default store;
// moduels/schedule.js
import { createReducer, createAction } from '@reduxjs/toolkit';
export const initialState = {
fullSchedule: []
};
export const fetchFullSchedule = createAction('FETCH_FULL_SCHEDULE');
const schedule = createReducer(initialState, {
[fetchFullSchedule]: (state, { payload }) => {
state.fullSchedule.push(payload);
}
});
export default schedule;
// store/configureStore.js
import {createWrapper} from 'next-redux-wrapper'
import { applyMiddleware, compose, createStore } from 'redux';
import reducer from '../reducers'
import {composeWithDevTools} from 'redux-devtools-extension'
const configureStore = ()=>{
// middle ware์ ์ฉ์
const middlewares = [];
const enhancer = process.env.NODE_ENV === 'production'
? compose(applyMiddleware(...middlewares))
: composeWithDevTools(
applyMiddleware(...middlewares),
);
//store ์์ฑ
const store = createStore(reducer, enhancer)
return store
}
const wrapper = createWrapper(configureStore,{
debug:process.env.NODE_ENV === 'development',
})
export default wrapper ;
//app.js
import Proptypes from 'prop-types';
import Head from 'next/head'
import wrapper from '../store/configureStore';
const App = ({ Component })=>{
return(
<>
<Head>
<title>๋ฆฌ์กํธ์ฑ</title>
</Head>
<Component />
</>
)
};
App.Proptypes = {
Component:Proptypes.elementType.isRequired
}
export default wrapper.withRedux(App);
export const CounterComponent = ({ value }) => {
const dispatch = useDispatch() //
return (
<div>
<span>{value}</span>
<button onClick={() => dispatch({ type: 'increment-counter' })}>
Increment counter
</button>
</div>
)
}
// loginForm.js - ๋ก๊ทธ์ธ
import { useDispatch,useSelector } from 'react-redux';
...
const onSubmitForm = useCallback(()=>{
dispatch(loginAction({id,password}))
},[id,password])
...
const {isLoggedIn} = useSelector((state)=> state.user)
๐reference