Redux
概述
JavaScript 状态容器,提供可预测化的状态管理。
const state = {
modelOpen: 'yes',
btnClicked: 'no',
btnActiveClass: 'active',
page: 5,
size: 10
}
核心概念及工作流程
Store:存储状态的容器,JavaScript 对象
View:视图,HTML 页面
Actions:对象,描述对状态进行怎样的操作
Reducers:函数,操作状态并返回新的状态
redux 计数器案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Redux</title>
</head>
<body>
<button id="J-plus">+</button>
<span id="J-count">0</span>
<button id="J-minus">-</button>
<script src="https://cdn.bootcdn.net/ajax/libs/redux/4.1.0/redux.min.js"></script>
<script>
// 3. 存储默认状态
const initialState = {
count: 0
};
// 2. 创建 reducer 函数
function reducer (state = initialState, action) {
switch (action.type) {
case 'increment':
return {
count: state.count + 1
}
case 'decrement':
return {
count: state.count - 1
}
default:
return state;
}
}
// 1. 创建 store 对象
const store = Redux.createStore(reducer);
// 4. 定义 action
const increment = { type: 'increment' };
const decrement = { type: 'decrement' };
// 5. 获取按钮,添加点击事件
document.getElementById('J-plus').onclick = function () {
// 6. 触发 action
store.dispatch(increment);
}
document.getElementById('J-minus').onclick = function () {
// 触发 action
store.dispatch(decrement);
}
// 7. 订阅 store
store.subscribe(() => {
document.getElementById('J-count').innerHTML = store.getState().count;
});
console.log(store); // dispatch: ƒ, subscribe: ƒ, getState: ƒ, replaceReducer: ƒ, @@observable: ƒ}
console.log(store.getState()); // {count: 0}
</script>
</body>
</html>
react 中 redux 解决的问题
在 React 中组件通信的数据流是单向的,顶层组件可以通过 props 属性向下层组件传递数据,而下层组件不能向上层传递数据,要实现下层组件修改数据,需要上层组件传递修改数据的方法到下层组件。当项目越来越大时,组件之间传递数据变得越来越困难。
使用 Redux 管理数据,由于 Store 独立于组件,使得数据管理独立于组件,解决了组件与组件之间传递数据困难的问题。
react 计数器
redux 工作流程
组件通过 dispatch 方法触发 Action。
Store 接收 Action 并将 Action 分发给 Reducer。
Reducer 根据 Action 类型对状态进行更改并将更改后的状态返回给 Store。
组件订阅 Store 状态,Store 中的状态更新会同步到组件。
安装
npm i redux react-redux
基本实现
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
const initialState = {
count: 0
}
function reducer (state = initialState, action) {
switch (action.type) {
case 'increment':
return {
count: state.count + 1
};
case 'decrement':
return {
count: state.count -1
};
default:
return state;
}
}
const store = createStore(reducer);
const increment = { type: 'increment' };
const decrement = { type: 'decrement' };
function Counter () {
return (
<div>
<button onClick={() => store.dispatch(increment)}>+</button>
<span>{ store.getState().count }</span>
<button onClick={() => store.dispatch(decrement)}>-</button>
</div>
)
}
store.subscribe(() => {
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
});
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
Provider 组件与 connect 方法
connect 方法:
- 订阅 store ,状态改变时重新渲染组件
- 获取 store 状态,将状态映射到组件的 props
- 获取 dispatch 方法
components/Counter.js
import React from "react"
import { connect } from 'react-redux';
function Counter ({ count, dispatch }) {
return (
<div>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<span>{ count }</span>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.count
})
export default connect(mapStateToProps)(Counter);
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import Counter from './components/Counter';
const initialState = {
count: 0
}
function reducer (state = initialState, action) {
switch (action.type) {
case 'increment':
return {
count: state.count + 1
};
case 'decrement':
return {
count: state.count -1
};
default:
return state;
}
}
const store = createStore(reducer);
const increment = { type: 'increment' };
const decrement = { type: 'decrement' };
ReactDOM.render(
<Provider store={store}>
<Counter />
</Provider>,
document.getElementById('root')
);
使用 connect 方法的第二个参数
import React from "react"
import { connect } from 'react-redux';
function Counter ({ count, increment, decrement }) {
return (
<div>
<button onClick={ increment }>+</button>
<span>{ count }</span>
<button onClick={ decrement }>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.count
});
const mapDispatchToProps = dispatch => ({
increment () {
dispatch({ type: 'increment' })
},
decrement () {
dispatch({ type: 'decrement' })
}
});
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
bindActionCreator 方法
store/actions/counter.js
export const increment = () => ({ type: 'increment' });
export const decrement = () => ({ type: 'decrement' });
components/Counter.js
import React from "react"
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as counterActions from '../store/actions/counter'
function Counter ({ count, increment, decrement }) {
return (
<div>
<button onClick={ increment }>+</button>
<span>{ count }</span>
<button onClick={ decrement }>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.count
});
const mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
代码重构 - 代码拆分
store/const/counter.js
export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
store/actions/counter.js
import { INCREMENT, DECREMENT } from "../const/counter";
export const increment = () => ({ type: INCREMENT });
export const decrement = () => ({ type: DECREMENT });
store/reducers/counter.js
import { INCREMENT, DECREMENT } from "../const/counter";
const initialState = {
count: 0
}
export function reducer (state = initialState, action) {
switch (action.type) {
case INCREMENT:
return {
count: state.count + 1
};
case DECREMENT:
return {
count: state.count -1
};
default:
return state;
}
}
store/index.js
import { createStore } from 'redux';
import { reducer } from './reducers/couner';
export const store = createStore(reducer);
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import Counter from './components/Counter';
import { store } from './store';
ReactDOM.render(
<Provider store={store}>
<Counter />
</Provider>,
document.getElementById('root')
);
action 传递参数
使用方法
传递参数
<button onClick={ () => increment(5) }>+</button>
接收参数,传递 reducer
export const increment = payload = ({ type: INCREMENT, payload });
reducer 根据接收到的数据进行处理
export default (state, action) => {
switch (action.type) {
case INCREMENT:
return { count: state.count + action.payload };
}
}
代码改造
component/Counter.js
import React from "react"
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as counterActions from '../store/actions/counter'
function Counter ({ count, increment, decrement }) {
return (
<div>
<button onClick={ () => increment(5) }>+</button>
<span>{ count }</span>
<button onClick={ () => decrement(5) }>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.count
});
const mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
store/actions/actions/counter.js
import { INCREMENT, DECREMENT } from "../const/counter";
export const increment = payload => ({ type: INCREMENT, payload });
export const decrement = payload => ({ type: DECREMENT, payload });
store/action/reducers/counter.js
import { INCREMENT, DECREMENT } from "../const/counter";
const initialState = {
count: 0
}
export function reducer (state = initialState, action) {
switch (action.type) {
case INCREMENT:
return {
count: state.count + action.payload
};
case DECREMENT:
return {
count: state.count - action.payload
};
default:
return state;
}
}
redux 弹出框案例
components/Modal.js
import React from "react";
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as modalActions from '../store/actions/modal';
function Modal ({ showStatus, show, hide }) {
const styles = {
width: 200,
height: 200,
position: 'absolute',
left: '50%',
top: '50%',
marginLeft: -100,
marginTop: -100,
background: 'orange',
display: showStatus ? 'block' : 'none'
};
return (
<div>
<button onClick={ show }>显示</button>
<button onClick={ hide }>隐藏</button>
<div style={styles}></div>
</div>
)
}
const mapStateToProps = state => ({
showStatus: state.show
});
const mapDispatchToProps = dispatch => bindActionCreators(modalActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Modal);
store/actions/modal.js
import { HIDE_MODAL, SHOW_MODAL } from "../const/modal";
export const show = () => ({ type: SHOW_MODAL });
export const hide = () => ({ type: HIDE_MODAL });
store/const/modal.js
export const SHOW_MODAL = 'showModal';
export const HIDE_MODAL = 'hideModal';
store/reducers/counter.js
import { INCREMENT, DECREMENT } from "../const/counter";
import { HIDE_MODAL, SHOW_MODAL } from "../const/modal";
const initialState = {
count: 0,
show: false
}
export function reducer (state = initialState, action) {
switch (action.type) {
case INCREMENT:
return {
...state,
count: state.count + action.payload
};
case DECREMENT:
return {
...state,
count: state.count - action.payload
};
case SHOW_MODAL:
return {
...state,
show: true
};
case HIDE_MODAL:
return {
...state,
show: false
};
default:
return state;
}
}
App.js
import React from "react";
import Counter from './components/Counter';
import Modal from './components/Modal';
function App () {
return (
<div>
<Counter />
<Modal />
</div>
)
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import { store } from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
拆分合并 reducer
components/Counter.js
import React from "react"
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as counterActions from '../store/actions/counter'
function Counter ({ count, increment, decrement }) {
return (
<div>
<button onClick={ () => increment(5) }>+</button>
<span>{ count }</span>
<button onClick={ () => decrement(5) }>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.counter.count // edit
});
const mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
components/Modal.js
import React from "react";
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as modalActions from '../store/actions/modal';
function Modal ({ showStatus, show, hide }) {
const styles = {
width: 200,
height: 200,
position: 'absolute',
left: '50%',
top: '50%',
marginLeft: -100,
marginTop: -100,
background: 'orange',
display: showStatus ? 'block' : 'none'
};
return (
<div>
<button onClick={ show }>显示</button>
<button onClick={ hide }>隐藏</button>
<div style={styles}></div>
</div>
)
}
const mapStateToProps = state => ({
showStatus: state.modal.show // edit
});
const mapDispatchToProps = dispatch => bindActionCreators(modalActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Modal);
store/reducers/counter.js
import { INCREMENT, DECREMENT } from "../const/counter";
const initialState = {
count: 0
}
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case INCREMENT:
return {
...state,
count: state.count + action.payload
};
case DECREMENT:
return {
...state,
count: state.count - action.payload
};
default:
return state;
}
};
export default counterReducer;
store/reducers/modal.js
import { HIDE_MODAL, SHOW_MODAL } from "../const/modal";
const initialState = {
show: false
}
const modalReducer = (state = initialState, action) => {
switch (action.type) {
case SHOW_MODAL:
return {
...state,
show: true
};
case HIDE_MODAL:
return {
...state,
show: false
};
default:
return state;
}
};
export default modalReducer;
store/reducers/index.js
import { combineReducers } from 'redux';
import CounterReducer from './counter';
import ModalReducer from './modal';
export default combineReducers({
counter: CounterReducer,
modal: ModalReducer
});
store/index.js
import { createStore } from 'redux';
import reducers from './reducers';
export const store = createStore(reducers);
中间件概念
中间件本质是一个函数,redux 允许我们通过中间件的方式扩展和增强 redux 应用程序。
开发 Redux 中间件
使用方法
模板代码
export default store => next => action => {};
注册中间件
import { } from 'redux';
import logger from './middlewares/logger';
createStore(reducer, applyMiddleware(
logger
));
案例
store/middleware/logger.js
const logger = store => next => action => {
console.log(action, store);
next(action);
};
export default logger;
store/middleware/test.js
const test = store => next => action => {
console.log('test running.');
next(action);
};
export default test;
store/index.js
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
import logger from './middleware/logger';
import test from './middleware/test';
export const store = createStore(reducers, applyMiddleware(logger, test));
中间件执行顺序取决于中间件注册顺序。
定义异步处理中间件
增加异步处理。
src/components/Counter.js
import React from "react"
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as counterActions from '../store/actions/counter'
function Counter ({ count, increment, decrement, increment_async }) {
return (
<div>
<button onClick={ () => increment_async(5) }>+ async</button>
<button onClick={ () => increment(5) }>+</button>
<span>{ count }</span>
<button onClick={ () => decrement(5) }>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.counter.count
});
const mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
src/components/Modal.js
import React from "react";
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as modalActions from '../store/actions/modal';
function Modal ({ showStatus, show, hide, show_async }) {
const styles = {
width: 200,
height: 200,
position: 'absolute',
left: '50%',
top: '50%',
marginLeft: -100,
marginTop: -100,
background: 'orange',
display: showStatus ? 'block' : 'none'
};
return (
<div>
<button onClick={ show_async }>显示-async</button>
<button onClick={ show }>显示</button>
<button onClick={ hide }>隐藏</button>
<div style={styles}></div>
</div>
)
}
const mapStateToProps = state => ({
showStatus: state.modal.show
});
const mapDispatchToProps = dispatch => bindActionCreators(modalActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Modal);
store/actions/counter.js
import { INCREMENT, DECREMENT } from "../const/counter";
export const increment = payload => ({ type: INCREMENT, payload });
export const decrement = payload => ({ type: DECREMENT, payload });
export const increment_async = payload => dispatch => {
setTimeout(() => dispatch(increment(payload)), 2 * 1000);
}
store/action/modal.js
import { HIDE_MODAL, SHOW_MODAL } from "../const/modal";
export const show = () => ({ type: SHOW_MODAL });
export const hide = () => ({ type: HIDE_MODAL });
export const show_async = () => dispatch => {
setTimeout(() => dispatch(show()), 2 * 1000);
}
store/middleware/thunk.js
const thunk = ({ dispatch }) => next => action => {
if (typeof action === 'function') {
return action(dispatch);
}
next(action);
}
export default thunk;
store/index.js
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
import logger from './middleware/logger';
import test from './middleware/test';
import thunk from './middleware/thunk';
export const store = createStore(reducers, applyMiddleware(logger, test, thunk));
redux-thunk 中间件
使用方法
yarn add redux-thunk
import thunk from 'redux-thunk';
import { applyMiddleware } from 'redux';
createStore(rootRouter, applyMiddleware(thunk));
const loadPosts = () => async dispatch => {
const posts = await axios.get('/api/posts').then(response => response.data);
dispatch({ type: LOADPOSTSUCCESS, payload: posts })
}
案例
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
import logger from './middleware/logger';
import test from './middleware/test';
// import thunk from './middleware/thunk';
import thunk from 'redux-thunk';
export const store = createStore(reducers, applyMiddleware(logger, test, thunk));
redux-saga 中间件
redux-saga 可以将异步操作从 Action Creator 文件中抽离出来,放在一个单独的文件中。
yarn add redux-saga
使用方法
创建 redux-saga 中间件
import createSagaMiddleware from 'redux-saga';
const sagaMiddleware = createSagaMiddleware();
注册 sagaMiddleware
createStore(reducer, applyMiddleware(sagaMiddleware));
使用 saga 接收 action 执行异步操作
import { takeEntry, put } from 'redux-saga/effects';
function* load_posts () {
const { data } = yield axios.get('/api/posts.json');
yield put(load_posts_success(data));
}
export default function* postSaga () {
yield takeEntry(LOAD_POSTS, load_posts);
}
启动 saga
import postSaga from './store/saga/post.saga';
sagaMiddleware.run(postSaga);
案例
components/Counter.js
import React from "react"
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as counterActions from '../store/actions/counter'
function Counter ({ count, increment, decrement, increment_async }) {
return (
<div>
<button onClick={ increment_async }>+</button>
<span>{ count }</span>
<button onClick={ () => decrement(5) }>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.counter.count
});
const mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
store/actions/counter.js
import { INCREMENT, DECREMENT, INCREMENT_ASYNC } from "../const/counter";
export const increment = payload => ({ type: INCREMENT, payload });
export const decrement = payload => ({ type: DECREMENT, payload });
// export const increment_async = payload => dispatch => {
// setTimeout(() => dispatch(increment(payload)), 2 * 1000);
// }
export const increment_async = () => ({ type: INCREMENT_ASYNC });
store/actions/const/counter.js
export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
export const INCREMENT_ASYNC = 'increment_async';
store/sagas/counter.js
import { takeEvery, put, delay } from 'redux-saga/effects';
import { increment } from '../actions/counter';
import { INCREMENT_ASYNC } from '../const/counter';
function* increament_async_fn () {
yield delay(2000);
yield put(increment(10));
}
const counterSaga = function* () {
yield takeEvery(INCREMENT_ASYNC, increament_async_fn)
}
export default counterSaga;
store/index.js
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
import createSagaMiddleware from 'redux-saga';
import counterSaga from './sagas/counter';
const sagaMiddleware = createSagaMiddleware();
export const store = createStore(reducers, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(counterSaga);
redux-saga action 传参
src/components/Counter.js
import React from "react"
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as counterActions from '../store/actions/counter'
function Counter ({ count, increment, decrement, increment_async }) {
return (
<div>
<button onClick={ () => increment_async(20) }>+</button>
<span>{ count }</span>
<button onClick={ () => decrement(5) }>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.counter.count
});
const mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
store/actions/counter.js
import { INCREMENT, DECREMENT, INCREMENT_ASYNC } from "../const/counter";
export const increment = payload => ({ type: INCREMENT, payload });
export const decrement = payload => ({ type: DECREMENT, payload });
// export const increment_async = payload => dispatch => {
// setTimeout(() => dispatch(increment(payload)), 2 * 1000);
// }
export const increment_async = payload => ({ type: INCREMENT_ASYNC, payload });
store/sagas/counter.js
import { takeEvery, put, delay } from 'redux-saga/effects';
import { increment } from '../actions/counter';
import { INCREMENT_ASYNC } from '../const/counter';
function* increament_async_fn (action) {
yield delay(2000);
yield put(increment(action.payload));
}
const counterSaga = function* () {
yield takeEvery(INCREMENT_ASYNC, increament_async_fn)
}
export default counterSaga;
saga 文件的拆分与合并
src/store/action/modal.js
import { HIDE_MODAL, SHOW_MODAL, SHOW_MODAL_ASYNC } from "../const/modal";
export const show = () => ({ type: SHOW_MODAL });
export const hide = () => ({ type: HIDE_MODAL });
// export const show_async = () => dispatch => {
// setTimeout(() => dispatch(show()), 2 * 1000);
// }
export const show_async = () => ({ type: SHOW_MODAL_ASYNC });
src/store/const/modal.js
export const SHOW_MODAL = 'showModal';
export const HIDE_MODAL = 'hideModal';
export const SHOW_MODAL_ASYNC = 'showModal_async';
src/store/sagas/counter.js
import { takeEvery, put, delay } from 'redux-saga/effects';
import { increment } from '../actions/counter';
import { INCREMENT_ASYNC } from '../const/counter';
function* increament_async_fn (action) {
yield delay(2000);
yield put(increment(action.payload));
}
const counterSaga = function* () {
yield takeEvery(INCREMENT_ASYNC, increament_async_fn);
}
export default counterSaga;
src/store/sagas/modal.js
import { takeEvery, put, delay } from 'redux-saga/effects';
import { show } from '../actions/modal';
import { SHOW_MODAL_ASYNC } from '../const/modal';
function* showModal_async () {
yield delay(2000);
yield put(show());
}
const modalSaga = function* () {
yield takeEvery(SHOW_MODAL_ASYNC, showModal_async);
}
export default modalSaga;
src/store/sagas/index.js
import { all } from 'redux-saga/effects';
import counterSaga from './counter';
import modalSaga from './modal';
const rootSaga = function* () {
yield all([
counterSaga(),
modalSaga()
]);
}
export default rootSaga;
src/store/index.js
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
import createSagaMiddleware from 'redux-saga';
import rootSaga from './sagas';
const sagaMiddleware = createSagaMiddleware();
export const store = createStore(reducers, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(rootSaga);
redux-action 中间件使用
redux 流程中存在大量的样板代码,使用 redux-actions 可以简化 Action 和 Reducer 的处理。
yarn add redux-actions
使用方法
创建 action
import { createAction } from 'redux-actions';
const increment_action = createAction('increment');
const decrement_action = createAction('decrement');
创建 reducer
import { handleActions as createReducer } from 'redux-actions';
import { increment_action, decrement_action } from '../actions/counter.js';
const initialState = { count: 0 };
const counterReducer = createReducer({
[increment_action]: (state, action) => ({ count: state.count + 1 }),
[decrement_action]: (state, action) => ({ count: state.count - 1 }),
}, initialState);
export default counterReducer;
案例
components/counter.js
import React from "react"
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as counterActions from '../store/actions/counter'
function Counter ({ count, increment, decrement}) {
return (
<div>
<button onClick={ () => increment(10) }>+</button>
<span>{ count }</span>
<button onClick={ () => decrement(10) }>-</button>
</div>
)
}
const mapStateToProps = state => ({
count: state.counter.count
});
const mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
store/action/counter.js
// import { INCREMENT, DECREMENT, INCREMENT_ASYNC } from "../const/counter";
// export const increment = payload => ({ type: INCREMENT, payload });
// export const decrement = payload => ({ type: DECREMENT, payload });
// // export const increment_async = payload => dispatch => {
// // setTimeout(() => dispatch(increment(payload)), 2 * 1000);
// // }
// export const increment_async = payload => ({ type: INCREMENT_ASYNC, payload });
import { createAction } from 'redux-actions';
export const increment = createAction('inrement');
export const decrement = createAction('decrement');
store/reducers/counter.js
// import { INCREMENT, DECREMENT } from "../const/counter";
// const initialState = {
// count: 0
// }
// const counterReducer = (state = initialState, action) => {
// switch (action.type) {
// case INCREMENT:
// return {
// ...state,
// count: state.count + action.payload
// };
// case DECREMENT:
// return {
// ...state,
// count: state.count - action.payload
// };
// default:
// return state;
// }
// };
// export default counterReducer;
import { handleActions as createReducer } from 'redux-actions';
import { increment, decrement } from '../actions/counter';
const initialState = {
count: 0
};
const handleIncrement = (state, action) => ({
count: state.count + action.payload
});
const handleDecrement = (state, action) => ({
count: state.count - action.payload
});
export default createReducer({
[increment]: handleIncrement,
[decrement]: handleDecrement
}, initialState);