Skip to content

Commit 67e3269

Browse files
author
kenberkeley
committed
refactor src/redux/
1 parent 656d054 commit 67e3269

File tree

26 files changed

+184
-154
lines changed

26 files changed

+184
-154
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
>
99
> ### 更新
1010
> 2016/8/28   引入 `cross-env` 解决跨平台问题,新增优化项 `DedupePlugin`
11-
> 2016/8/29   重命名 `makeContainer / makeReducer.js => createContainer / createReducer.js`
11+
> 2016/8/29   重命名 `makeContainer / makeReducer.js => createContainer / createReducer.js`
12+
> 2016/9/10   重构 `src/redux/`
1213
1314
## 目录
1415
#### § [技术栈](#features)
@@ -221,7 +222,7 @@
221222
[alias-intro]: https://github.com/kenberkeley/vue-demo#alias
222223
[createContainer]: https://github.com/kenberkeley/react-demo/blob/master/src/utils/createContainer.js
223224
[Navbar]: https://github.com/kenberkeley/react-demo/blob/master/src/components/Navbar/index.js
224-
[connect]: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options
225+
[connect]: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options
225226
[dan-post]: https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
226227
[chrome-extension]: https://github.com/zalmoxisus/redux-devtools-extension
227228
[devtools-component]: https://github.com/gaearon/redux-devtools

src/app.js

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
/* 入口启动文件 */
22
import React from 'react'
33
import ReactDOM from 'react-dom'
4-
import App from 'COMPONENT/App'
4+
import { Provider } from 'react-redux'
5+
import { Router } from 'react-router'
6+
import store, { history } from 'STORE'
7+
import routes from 'ROUTE'
58

69
/**
710
* 下面这货用于检测不必要的重新渲染,详情请看其项目地址:
811
* https://github.com/garbles/why-did-you-update
912
*
10-
* 有关性能提升方面的问题,之后我会总结出来
11-
* (诸如 PureComponent / shouldComponentUpdate / Immutable.js 等)
13+
* 有关性能提升方面的问题
14+
* 诸如 PureComponent / shouldComponentUpdate / Immutable.js 等
15+
* 请自行查阅相关资料
1216
*/
1317
if (__DEV__ && __WHY_DID_YOU_UPDATE__) {
1418
const { whyDidYouUpdate } = require('why-did-you-update')
@@ -24,7 +28,32 @@ if (__PROD__) {
2428
// ================================
2529
// 将根组件挂载到 DOM,启动!
2630
// ================================
31+
const MOUNT_NODE = document.getElementById('app')
32+
2733
ReactDOM.render(
28-
<App />,
29-
document.getElementById('app')
34+
<Provider store={store}>
35+
<Router history={history} children={routes} />
36+
</Provider>,
37+
MOUNT_NODE
3038
)
39+
40+
/**
41+
* 【拓展】
42+
* react-redux 的 Provider 中传入的属性
43+
* 可以让全体组件轻松访问,避免繁琐累赘的层层下传。例子:
44+
*
45+
* class XXX extends Component {
46+
* static contextTypes = {
47+
* // 组件中需要这样子声明
48+
* store: PropTypes.object.isRequired
49+
* }
50+
* componentDidMount () {
51+
* // 之后就可以直接这样用
52+
* this.context.store.getState()
53+
* }
54+
* }
55+
*
56+
* 但上面这种官方的做法实在太麻烦,于是我们有更为直接的方式:
57+
* import store from 'STORE'
58+
* store.getState() // 只读,更改 state 只能通过 dispatch
59+
*/

src/components/404.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default class NotFound extends Component {
1111
}
1212

1313
render () {
14-
// 非实体组件需显式返回null
14+
// 非实体组件需显式返回 null
1515
return null
1616
}
1717
}

src/components/App.js

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,23 @@
11
import React from 'react'
2-
import { Provider } from 'react-redux'
3-
import { Router } from 'react-router'
4-
import { store, history } from 'STORE'
5-
import routes from 'ROUTE'
2+
import Navbar from 'COMPONENT/Navbar/'
63

7-
const App = () => (
8-
<Provider store={store}>
9-
<Router history={history} children={routes} />
10-
</Provider>
4+
let DevTools
5+
if (__DEV__ && __COMPONENT_DEVTOOLS__) {
6+
// 组件形式的 Redux DevTools
7+
DevTools = require('COMPONENT/DevTools').default
8+
}
9+
10+
const App = ({ children, location }) => (
11+
<div>
12+
<Navbar location={location} />
13+
14+
<div className="container">
15+
{/* 相当于 Vue Demo 中的根 router-view */}
16+
{ children }
17+
</div>
18+
19+
{ DevTools && <DevTools /> }
20+
</div>
1121
)
1222

1323
export default App
14-
15-
/**
16-
* 【拓展】
17-
* Provider 中传入的属性,可以让全体组件轻松访问,避免繁琐累赘的层层下传。例子:
18-
*
19-
* class XXX extends Component {
20-
* static contextTypes = {
21-
* // 组件中需要这样子声明
22-
* store: PropTypes.object.isRequired
23-
* }
24-
* componentDidMount () {
25-
* // 之后就可以直接这样用
26-
* this.context.store.getState()
27-
* }
28-
* }
29-
*
30-
* 但上面这种官方的做法实在太麻烦,于是我们有更为直接的方式:
31-
* import store from 'STORE'
32-
* store.getState() // 注意:此仅为只读,更改 state 只能通过 dispatch
33-
*/

src/components/Msg/MsgDetail.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import msgService from 'SERVICE/msgService'
66

77
export default class MsgDetail extends Component {
88
/**
9-
* 有关Context的用法请看文档:https://facebook.github.io/react/docs/context.html
9+
* 有关 Context 的用法请看文档:https://facebook.github.io/react/docs/context.html
1010
* 实际上可不引入 this.context.router,直接使用 this.props.history 即可
1111
* 但控制台会报 Warning: [react-router] `props.history` and `context.history` are deprecated. Please use `context.router`. http://tiny.cc/router-contextchanges
1212
*/

src/components/Msg/MsgForm/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React, { Component, PropTypes } from 'react'
22
import msgService from 'SERVICE/msgService'
33
import handleChange from 'MIXIN/handleChange'
4-
import tpl from './msg-form.jsx' // 分拆写JSX模板以减少单文件代码量
4+
import tpl from './msg-form.jsx' // 分拆写 JSX 模板以减少单文件代码量
55

66
/* 为什么不直接 const initState = { ... } 而是用函数返回呢?
7-
皆因直接传initState仅是传引用,initState 本身可被修改 */
7+
皆因直接传 initState 仅是传引用,initState 本身可被修改 */
88
const getInitState = () => ({ id: '', title: '', content: '' })
99

1010
/* 由于本组件由 /msg/add 与 /msg/:msgId 所公用

src/components/Msg/MsgList/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import dateTimeFormatter from 'UTIL/dateTimeFormatter'
99
export default class MsgList extends Component {
1010
componentWillMount () {
1111
let { author } = this.props.location.query
12-
if (author) this.props.specifyAuthor(author)
12+
this.props.specifyAuthor(author)
1313
this.updateMsgList()
1414
}
1515
/**

src/components/Msg/OptBtnGroup.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { Component, PropTypes } from 'react'
22
import { Link } from 'react-router'
33

4-
/* 本组件全称Operation Button Group,操作按钮组 */
4+
/* 本组件全称 Operation Button Group,操作按钮组 */
55
export default class OptBtnGroup extends Component {
66
static contextTypes = {
77
router: PropTypes.object.isRequired

src/components/Navbar/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default class Navbar extends Component {
2020
render () {
2121
let {
2222
userData, login, logout, // 通过 connect 获取
23-
location: { pathname } // 通过 LayoutView 传入
23+
location: { pathname } // 通过 App 传入
2424
} = this.props
2525

2626
return (

src/components/Redirect.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class Redirect extends Component {
2121
}
2222

2323
render () {
24-
// 非实体组件需显式返回null
24+
// 非实体组件需显式返回 null
2525
return null
2626
}
2727
}

src/components/Todo/index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ export default class Todo extends Component {
99
}
1010

1111
render () {
12-
let { todos, addTodo } = this.props
12+
let { todos, addTodo, toggleTodo } = this.props
1313
return (
1414
<div>
1515
<ul>
1616
{ todos.map(todo =>
17-
<li key={todo.id}>
18-
{ todo.content }
17+
<li key={todo.id} onClick={() => toggleTodo(todo.id)}>
18+
<span style={{textDecoration: todo.completed ? 'line-through' : 'none'}}>
19+
{ todo.content }
20+
</span>
1921
<a href="javascript:;"
2022
style={{textDecoration: 'none'}}
2123
className="pull-right"

src/redux/actions/todo.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// ================================
22
// Action Type
33
// ================================
4-
export const ADD_TODO = 'ADD_TODO'
5-
export const DEL_TODO = 'DEL_TODO'
4+
const ADD_TODO = 'ADD_TODO'
5+
const DEL_TODO = 'DEL_TODO'
6+
const TOGGLE_TODO = 'TOGGLE_TODO'
67

78
// ================================
89
// Action Creator
@@ -12,10 +13,16 @@ const addTodo = (content) => ({
1213
payload: {
1314
id: setTimeout(() => {}), // 生成唯一 ID 的一种方式
1415
content,
16+
completed: false,
1517
createdAt: Date.now()
1618
}
1719
})
1820

21+
const toggleTodo = (todoId) => ({
22+
type: TOGGLE_TODO,
23+
payload: todoId
24+
})
25+
1926
const delTodo = (todoId) => ({
2027
type: DEL_TODO,
2128
payload: todoId
@@ -26,7 +33,7 @@ export default {
2633
// 虽然是同步的函数,但请不要自行 bindActionCreators
2734
// 皆因调用 connect 后,react-redux 已经帮我们做了,见:
2835
// https://github.com/reactjs/react-redux/blob/master/src/utils/wrapActionCreators.js
29-
addTodo, delTodo
36+
addTodo, toggleTodo, delTodo
3037
}
3138

3239
// ================================
@@ -38,7 +45,10 @@ export default {
3845
// ================================
3946
export const ACTION_HANDLERS = {
4047
[ADD_TODO]: (todos, { payload }) => [ ...todos, payload ],
41-
[DEL_TODO]: (todos, { payload }) => todos.filter(
42-
todo => todo.id !== payload // payload is todoId
48+
[TOGGLE_TODO]: (todos, { payload: todoId }) => todos.map(
49+
todo => todo.id === todoId ? { ...todo, completed: !todo.completed } : todo
50+
),
51+
[DEL_TODO]: (todos, { payload: todoId }) => todos.filter(
52+
todo => todo.id !== todoId
4353
)
4454
}

src/redux/store/enhancers.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// ======================================================
2+
// 配置 Store 增强器
3+
// ======================================================
4+
const enhancers = []
5+
6+
if (__DEV__) {
7+
/** Redux DevTools **/
8+
9+
/* 1. Chrome 插件 Redux DevTools(默认)
10+
P.S: 独立窗口可调用 window.devToolsExtension.open() */
11+
if (!__COMPONENT_DEVTOOLS__) {
12+
const devToolsExtension = window.devToolsExtension
13+
if (typeof devToolsExtension === 'function') {
14+
enhancers.push(devToolsExtension())
15+
}
16+
}
17+
18+
/* 2. 内嵌在页面中的 Redux DevTools 组件 */
19+
if (__COMPONENT_DEVTOOLS__) {
20+
const DevTools = require('COMPONENT/DevTools').default
21+
enhancers.push(DevTools.instrument())
22+
}
23+
}
24+
25+
export default enhancers

src/redux/store/index.js

Lines changed: 7 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,23 @@
1-
import { routerMiddleware, syncHistoryWithStore } from 'react-router-redux'
2-
import createBrowserHistory from 'history/lib/createBrowserHistory'
31
import { applyMiddleware, compose, createStore } from 'redux'
4-
import { useRouterHistory } from 'react-router'
5-
import thunk from 'redux-thunk'
62
import { createRootReducer } from 'REDUCER'
7-
8-
// ========================================================
9-
// 浏览器 history 配置
10-
// ========================================================
11-
const browserHistory = useRouterHistory(createBrowserHistory)({
12-
basename: '' // 相当于 rootPath
13-
})
14-
15-
// ======================================================
16-
// 配置中间件
17-
// ======================================================
18-
const middlewares = [thunk, routerMiddleware(browserHistory)]
19-
if (__DEV__) {
20-
/** Redux Logger (P.S: 打印日志会造成轻微的卡顿) **/
21-
const createLogger = require('redux-logger')
22-
middlewares.push(createLogger())
23-
}
24-
25-
// ======================================================
26-
// 配置 Store 增强器
27-
// ======================================================
28-
const enhancers = []
29-
if (__DEV__) {
30-
/** Redux DevTools **/
31-
32-
/* 1. Chrome 插件 Redux DevTools(默认)
33-
P.S: 独立窗口可调用 window.devToolsExtension.open() */
34-
if (!__COMPONENT_DEVTOOLS__) {
35-
const devToolsExtension = window.devToolsExtension
36-
if (typeof devToolsExtension === 'function') {
37-
enhancers.push(devToolsExtension())
38-
}
39-
}
40-
41-
/* 2. 内嵌在页面中的 Redux DevTools 组件 */
42-
if (__COMPONENT_DEVTOOLS__) {
43-
const DevTools = require('COMPONENT/DevTools').default
44-
enhancers.push(DevTools.instrument())
45-
}
46-
}
3+
import middlewares from './middlewares'
4+
import enhancers from './enhancers'
5+
import syncHistoryWithStore from './syncHistoryWithStore'
476

487
// ======================================================
498
// 实例化 Store
509
// ======================================================
51-
export const store = createStore(
10+
const store = createStore(
5211
createRootReducer(),
5312
window.__INITIAL_STATE__ || {}, // 前后端同构(服务端渲染)数据同步
5413
compose(
5514
applyMiddleware(...middlewares),
5615
...enhancers
5716
)
5817
)
18+
export default store
5919

6020
// ======================================================
61-
// 配置 history 同步
21+
// 增强版 history
6222
// ======================================================
63-
export const history = syncHistoryWithStore(
64-
browserHistory,
65-
store,
66-
{ selectLocationState: (state) => state.router }
67-
)
68-
69-
export default store
23+
export const history = syncHistoryWithStore(store)

src/redux/store/initState.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,26 @@
22
* 本文件的作用就是直观呈现 整个应用状态结构树 及其 初始值
33
*/
44
export default {
5-
/* 用户session */
5+
/* 用户 session */
66
userData: null,
77

88
/* 留言板模块(按需加载) */
99
msg: {
1010
msgs: [], // 当前显示的留言列表
1111
displayControl: { // 查询条件
12-
pageIdx: 1, // 默认是第10页
13-
quantity: 10, // 默认每页展示10条记录
12+
pageIdx: 1, // 默认是第 10 页
13+
quantity: 10, // 默认每页显示 10 条记录
1414
authorSpecified: '' // 是否有指定发布者
1515
}
1616
},
1717

1818
/* 待办事项模块(按需加载) */
19-
todos: []
19+
todos: [
20+
// {
21+
// id: 123,
22+
// content: '待办事项1',
23+
// completed: false,
24+
// createdAt: 1473499991348
25+
// }
26+
]
2027
}

0 commit comments

Comments
 (0)