Skip to content

Commit

Permalink
link react redux
Browse files Browse the repository at this point in the history
  • Loading branch information
huangtengfei committed May 24, 2016
1 parent 49c3426 commit aa4183b
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 75 deletions.
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,45 @@ npm run dev

打开 http://localhost:8080 即可看到效果。

## 实现过程

a. 首先,明确应用中对象的结构。对于 todo,需要保存两种数据,所有的任务 `todos` 和 筛选条件 `filter`,这些就是要定义在 state 中的。

b. 明确应用需要哪些操作。对于 todo,有新建 todo、切换 todo 状态和设置筛选条件三种,写好 actions。

c. 明确当有 action 发生时,state 是如何相应改变的。比如新建 todo,就在 todos 中加一条;改变筛选条件时,就将 filter 改成新的条件。根据 state 字段的不同,拆分成不同的 reducer 处理,写好 reducers。

d. 在 store 中将 actions 和 reducers 联系在一起。此时还没有应用的界面,但可以测试一下数据处理逻辑。这个文件通常是 **应用的入口**

e. 写 React 组件。要注意,首先想好哪些是容器组件(聪明组件),哪些是展示组件(傻瓜组件)。容器组件一般是在最上层,它从 Redux 获取 state 并向 Redux 派发 actions,这个文件也通常是 **组件的入口**。展示组件会根据应用的大小进行拆分,比如对于 todo,拆成 AddTodo、TodoList、Todo 和 TodoFilter 四个展示组件,它们从 props 获取数据和调用回调函数。

f. 连接到 Redux。主要有两步,一步是在 应用的入口 文件中将根组件包在 `<Provider>` 中;一步是在 组件的入口 文件中用 `connect()` 包装组件,将前面写 React 组件模拟用的 state 数据源替换成包装组件从 Redux 获取的 state。

这样实现下来,一个简单的 Redux Demo 的目录结构大概如此:

```
--redux-demo
|--components(组件目录)
|--Todo
|--actions.js
|--reducers.js
|--index.js (应用的入口)
|--AddTodo.jsx
|--TodoList.jsx
|--Todo.jsx
|--TodoFilter.jsx
|--App.jsx (组件的入口)
|--index.less
|--index.js(入口文件)
|--build(输出目录)
|--index.html
|--bundle.js(输出文件,由 webpack 打包后生成的)
|--package.json
|--webpack.config.js
```

下面内容是我学习 Redux 的笔记和总结。

## Redux 基础

与 Flux 相比,Redux 将 Dispatcher 和 Action、Store 解耦,使 Action 变成了一个纯粹的简单对象,使 Store 变成了一个 pure function(no side-effects,对一个相同的输入无论何时总返回相同结果)。
Expand Down Expand Up @@ -172,7 +211,7 @@ react-redux 只有两个 API,即 `<Provider>` 和 `Connect` 。

```javascript
render(
<Provider>
<Provider store={store}>
<App />
</Provider>,
rootElement
Expand Down
86 changes: 27 additions & 59 deletions components/Todo/App.jsx
Original file line number Diff line number Diff line change
@@ -1,79 +1,47 @@

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { connect } from 'react-redux'

import AddTodo from './AddTodo.jsx'
import TodoList from './TodoList.jsx'
import TodoFilter from './TodoFilter.jsx'

class App extends Component {

constructor() {
super()
this.onAddClick = this.onAddClick.bind(this)
this.onToggleClick = this.onToggleClick.bind(this)
this.onFilterChange = this.onFilterChange.bind(this)

this.state = {};
this.state.todos = [{
text: 'learn about react',
completed: true
},{
text: 'learn redux',
completed: false
}]
this.state.filter = 'SHOW_ALL'

this.filteredTodos = this.state.todos
}
import { addTodo, toggleTodo, setFilter, Filters } from './actions.js'

onAddClick(input) {
let newTodo = {
text: input,
completed: false
}
let todos = this.state.todos
let newTodos = todos.concat([newTodo])
this.setState({todos: newTodos})
this.filterTodos(newTodos, this.state.filter)
}

onToggleClick(index) {
let todos = this.state.todos
let newTodos = [...todos]
newTodos[index].completed = !newTodos[index].completed
this.setState({todos: newTodos})
}

onFilterChange(filter) {
this.setState({filter: filter})
this.filterTodos(this.state.todos, filter)
}

filterTodos(todos, filter) {
this.filteredTodos = todos;
if(filter == 'SHOW_COMPLETED') {
this.filteredTodos = todos.filter((todo) => {
return todo.completed
})
}else if(filter == 'SHOW_ACTIVE') {
this.filteredTodos = todos.filter((todo) => {
return !todo.completed
})
}
}
class App extends Component {

render() {
const { dispatch, filteredTodos, filter } = this.props
return (
<div>
<AddTodo onAddClick={this.onAddClick} />
<TodoList todos={this.filteredTodos} onToggleClick={this.onToggleClick} />
<TodoFilter filter={this.state.filter} onFilterChange={this.onFilterChange} />
<AddTodo onAddClick={(text) => dispatch(addTodo(text))} />
<TodoList todos={filteredTodos} onToggleClick={(index) => dispatch(toggleTodo(index))} />
<TodoFilter filter={filter} onFilterChange={(filter) => dispatch(setFilter(filter))} />
</div>
)
}

}

ReactDOM.render(<App />, document.getElementById('todo'))
function filterTodos(todos, filter) {
switch(filter) {
case Filters.SHOW_ALL:
return todos;
case Filters.SHOW_COMPLETED:
return todos.filter(todo => todo.completed)
case Filters.SHOW_ACTIVE:
return todos.filter(todo => !todo.completed)
}
}

function select(state) {
console.log(state)
return {
filteredTodos: filterTodos(state.todos, state.filter),
filter: state.filter
}
}

export default connect(select)(App)

23 changes: 10 additions & 13 deletions components/Todo/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@

import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'

import todoApp from './reducers.js'

import { addTodo, toggleTodo, setFilter, Filters } from './actions.js'
import App from './App.jsx'

let store = createStore(todoApp)

let unsubscribe = store.subscribe(() => {
console.log(store.getState())
})

store.dispatch(addTodo('build a react app'))
store.dispatch(addTodo('build a redux app'))
store.dispatch(toggleTodo(1))
store.dispatch(setFilter(Filters.SHOW_ACTIVE))

unsubscribe();
store.dispatch(addTodo('build a todo app'))
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('todo')
)
4 changes: 2 additions & 2 deletions components/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

// import Counter from './Counter/index.js'

// import Todo from './Todo/index.js'
import Todo from './Todo/index.js'

import App from './Todo/App.jsx'
// import App from './Todo/App.jsx'

import './Todo/index.less'

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"marked": "^0.3.5",
"react": "^15.0.2",
"react-dom": "^15.0.2",
"react-redux": "^4.4.5",
"redux": "^3.5.2"
},
"devDependencies": {
Expand Down

0 comments on commit aa4183b

Please sign in to comment.