diff --git a/README.md b/README.md index 4dd2b0a..f17eb00 100644 --- a/README.md +++ b/README.md @@ -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。主要有两步,一步是在 应用的入口 文件中将根组件包在 `` 中;一步是在 组件的入口 文件中用 `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,对一个相同的输入无论何时总返回相同结果)。 @@ -172,7 +211,7 @@ react-redux 只有两个 API,即 `` 和 `Connect` 。 ```javascript render( - + , rootElement diff --git a/components/Todo/App.jsx b/components/Todo/App.jsx index 5a2a22e..20b587a 100644 --- a/components/Todo/App.jsx +++ b/components/Todo/App.jsx @@ -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 (
- - - + dispatch(addTodo(text))} /> + dispatch(toggleTodo(index))} /> + dispatch(setFilter(filter))} />
) } } -ReactDOM.render(, 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) diff --git a/components/Todo/index.js b/components/Todo/index.js index 7544253..804bb52 100644 --- a/components/Todo/index.js +++ b/components/Todo/index.js @@ -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')) \ No newline at end of file +render( + + + , + document.getElementById('todo') +) \ No newline at end of file diff --git a/components/index.js b/components/index.js index ef41f8a..8d34a63 100644 --- a/components/index.js +++ b/components/index.js @@ -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' diff --git a/package.json b/package.json index 9ec7277..019b66f 100644 --- a/package.json +++ b/package.json @@ -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": {