用redux完成事务清单
今天再来一个例子,我们从组件开始。
App.js
import React, { PropTypes } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Header from '../components/Header'
import MainSection from '../components/MainSection'
import * as TodoActions from '../actions'
const App = ({todos, actions}) => (
<div>
<Header addTodo={actions.addTodo} /> //头部负责添加事项
<MainSection todos={todos} actions={actions} /> //这是2个组件
</div>
)
App.propTypes = {
todos: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired //todos是数组 actions是对象
}
const mapStateToProps = state => ({
todos: state.todos
})
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(TodoActions, dispatch)
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)
head.js
import React, { PropTypes, Component } from 'react'
import TodoTextInput from './TodoTextInput'
export default class Header extends Component { //es6组建写法
static propTypes = {
addTodo: PropTypes.func.isRequired
}
handleSave = text => {
if (text.length !== 0) {
this.props.addTodo(text)
}
}
render() {
return (
<header className="header">
<h1>todos</h1>
<TodoTextInput newTodo
onSave={this.handleSave} //添加事项
placeholder="What needs to be done?" />
</header>
)
}
}
TodoTextInput.js
import React, { Component, PropTypes } from 'react'
import classnames from 'classnames'
export default class TodoTextInput extends Component {
static propTypes = {
onSave: PropTypes.func.isRequired,
text: PropTypes.string,
placeholder: PropTypes.string,
editing: PropTypes.bool,
newTodo: PropTypes.bool
}
state = {
text: this.props.text || ''
}
handleSubmit = e => {
const text = e.target.value.trim()
if (e.which === 13) {
this.props.onSave(text) //保存文本值
if (this.props.newTodo) {
this.setState({ text: '' })
}
}
}
handleChange = e => {
this.setState({ text: e.target.value })
}
handleBlur = e => {
if (!this.props.newTodo) {
this.props.onSave(e.target.value)
}
}
render() {
return (
<input className={
classnames({
edit: this.props.editing,
'new-todo': this.props.newTodo
})}
type="text"
placeholder={this.props.placeholder} //what needs to be done?
autoFocus="true"
value={this.state.text}
onBlur={this.handleBlur}
onChange={this.handleChange} //改变state里面的值
onKeyDown={this.handleSubmit} /> //keycode=13 提交保存
)
}
}
mainSection.js
import React, { Component, PropTypes } from 'react'
import TodoItem from './TodoItem'
import Footer from './Footer'
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters' //过滤器
const TODO_FILTERS = {
[SHOW_ALL]: () => true,
[SHOW_ACTIVE]: todo => !todo.completed,
[SHOW_COMPLETED]: todo => todo.completed
}
export default class MainSection extends Component {
static propTypes = {
todos: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
}
state = { filter: SHOW_ALL }
handleClearCompleted = () => {
this.props.actions.clearCompleted() //清除完成事项
}
handleShow = filter => {
this.setState({ filter }) //根据过滤条件展示
}
renderToggleAll(completedCount) {
const { todos, actions } = this.props
if (todos.length > 0) {
return (
<input className="toggle-all"
type="checkbox"
checked={completedCount === todos.length} //是否全部完成
onChange={actions.completeAll} />
)
}
}
renderFooter(completedCount) {
const { todos } = this.props
const { filter } = this.state
const activeCount = todos.length - completedCount
if (todos.length) {
return (
<Footer completedCount={completedCount}
activeCount={activeCount}
filter={filter}
onClearCompleted={this.handleClearCompleted.bind(this)}
onShow={this.handleShow.bind(this)} />
)
}
}
render() {
const { todos, actions } = this.props
const { filter } = this.state
const filteredTodos = todos.filter(TODO_FILTERS[filter]) //初始值为showall 展示全部
const completedCount = todos.reduce((count, todo) => //统计已完成事项
todo.completed ? count + 1 : count,
0
)
return (
<section className="main">
{this.renderToggleAll(completedCount)}
<ul className="todo-list">
{filteredTodos.map(todo =>
<TodoItem key={todo.id} todo={todo} {...actions} />
)}
</ul>
{this.renderFooter(completedCount)}
</section>
)
}
}
todoItems.js
import React, { Component, PropTypes } from 'react'
import classnames from 'classnames'
import TodoTextInput from './TodoTextInput'
export default class TodoItem extends Component {
static propTypes = {
todo: PropTypes.object.isRequired,
editTodo: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired,
completeTodo: PropTypes.func.isRequired
}
state = {
editing: false
}
handleDoubleClick = () => {
this.setState({ editing: true })
}
handleSave = (id, text) => {
if (text.length === 0) {
this.props.deleteTodo(id)
} else {
this.props.editTodo(id, text) //编辑 不存在text则删除该项
}
this.setState({ editing: false })
}
render() {
const { todo, completeTodo, deleteTodo } = this.props
let element
if (this.state.editing) {
element = (
<TodoTextInput text={todo.text}
editing={this.state.editing}
onSave={(text) => this.handleSave(todo.id, text)} />
)
} else {
element = (
<div className="view">
<input className="toggle"
type="checkbox"
checked={todo.completed}
onChange={() => completeTodo(todo.id)} />
<label onDoubleClick={this.handleDoubleClick}> //双击修改为可编辑状态 会重新渲染
{todo.text}
</label>
<button className="destroy"
onClick={() => deleteTodo(todo.id)} />
</div>
)
}
return (
<li className={classnames({
completed: todo.completed,
editing: this.state.editing
})}>
{element}
</li>
)
}
}
footer.js
import React, { PropTypes, Component } from 'react'
import classnames from 'classnames'
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters'
const FILTER_TITLES = {
[SHOW_ALL]: 'All',
[SHOW_ACTIVE]: 'Active',
[SHOW_COMPLETED]: 'Completed'
}
export default class Footer extends Component {
static propTypes = {
completedCount: PropTypes.number.isRequired,
activeCount: PropTypes.number.isRequired,
filter: PropTypes.string.isRequired,
onClearCompleted: PropTypes.func.isRequired,
onShow: PropTypes.func.isRequired
}
renderTodoCount() {
const { activeCount } = this.props
const itemWord = activeCount === 1 ? 'item' : 'items' //此处语法经典
return (
<span className="todo-count">
<strong>{activeCount || 'No'}</strong> {itemWord} left //有多少未完成事项
</span>
)
}
renderFilterLink(filter) {
const title = FILTER_TITLES[filter]
const { filter: selectedFilter, onShow } = this.props
return (
<a className={classnames({ selected: filter === selectedFilter })}
style={{ cursor: 'pointer' }}
onClick={() => onShow(filter)}>
{title}
</a>
)
}
renderClearButton() {
const { completedCount, onClearCompleted } = this.props
if (completedCount > 0) {
return (
<button className="clear-completed"
onClick={onClearCompleted} >
Clear completed
</button>
)
}
}
render() {
return (
<footer className="footer">
{this.renderTodoCount()}
<ul className="filters">
{[ SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED ].map(filter =>
<li key={filter}>
{this.renderFilterLink(filter)} //切换不同的过滤条件
</li>
)}
</ul>
{this.renderClearButton()}
</footer>
)
}
}
好了 这就是组件 比上次有点多 不过当成是训练 最重要的是把握整体结构
indes.js
import * as types from '../constants/ActionTypes'
export const addTodo = text => ({ type: types.ADD_TODO, text })
export const deleteTodo = id => ({ type: types.DELETE_TODO, id })
export const editTodo = (id, text) => ({ type: types.EDIT_TODO, id, text }) //这一看就是dispatch的内容
export const completeTodo = id => ({ type: types.COMPLETE_TODO, id })
export const completeAll = () => ({ type: types.COMPLETE_ALL })
export const clearCompleted = () => ({ type: types.CLEAR_COMPLETED })
todo.js
import { ADD_TODO, DELETE_TODO, EDIT_TODO, COMPLETE_TODO, COMPLETE_ALL, CLEAR_COMPLETED } from '../constants/ActionTypes'
const initialState = [
{
text: 'Use Redux',
completed: false,
id: 0 //初始化state
}
]
export default function todos(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return [
{
id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1, //确定id值
completed: false,
text: action.text
},
...state
]
case DELETE_TODO:
return state.filter(todo =>
todo.id !== action.id
)
case EDIT_TODO:
return state.map(todo =>
todo.id === action.id?
(...todo,{text:action.text}):
todo
)
case COMPLETE_TODO:
return state.map(todo =>
todo.id === action.id ?
{ ...todo, completed: !todo.completed } : //用于切换
todo
)
case COMPLETE_ALL:
const areAllMarked = state.every(todo => todo.completed) //全部完成 或全部未完成
return state.map(todo => ({
...todo,
completed: !areAllMarked
}))
case CLEAR_COMPLETED:
return state.filter(todo => todo.completed === false)
default:
return state
}
}
index.js 整合reducers
import { combineReducers } from 'redux'
import todos from './todos'
const rootReducer = combineReducers({
todos
})
export default rootReducer
好了 代码就这么多 这一次reducers倒不是很复杂 反倒组件有点乱 总之是单向数据流动,根据action的类型做出相应的改变,最后重新render。。。
用redux完成事务清单的更多相关文章
- 内容提供者 ContentResolver 数据库 示例 -1
MainActivity public class MainActivity extends ListActivity { private TextView tv_info; priv ...
- Spring Transaction 使用入门 (转)
Spring Transaction 使用入门 一.开篇陈述 1.1 写文缘由 最近在系统学习spring框架IoC.AOP.Transaction相关的知识点,准备写三篇随笔记录学习过程中的感悟.这 ...
- Spring Transaction 使用入门
一.开篇陈述 1.1 写文缘由 最近在系统学习spring框架IoC.AOP.Transaction相关的知识点,准备写三篇随笔记录学习过程中的感悟.这是第一篇,记录spring Transactio ...
- 如何查找SAP的事务代码清单
SAP系统中,为了省去输入程序名称等繁琐步骤,SAP提供一种命令,称作‘事务代码’,通过执行事务代码达到快速进入相应程序的目的.那么在系统中如何去查找事务代码,事务代码和程序的对应关系如何呢?我们可以 ...
- SAP MM事务代码清单
- react+redux教程(七)自定义redux中间件
今天,我们要讲解的是自定义redux中间件这个知识点.本节内容非常抽象,特别是中间件的定义原理,那多层的函数嵌套和串联,需要极强逻辑思维能力才能完全消化吸收.不过我会多罗嗦几句,所以不用担心. 例子 ...
- react+redux教程(四)undo、devtools、router
上节课,我们介绍了一些es6的新语法:react+redux教程(三)reduce().filter().map().some().every()....展开属性 今天我们通过解读redux-undo ...
- angular开发者吐槽react+redux的复杂:“一个demo证明你的开发效率低下”
曾经看到一篇文章,写的是jquery开发者吐槽angular的复杂.作为一个angular开发者,我来吐槽一下react+redux的复杂. 例子 为了让大家看得舒服,我用最简单的一个demo来展示r ...
- 6周学习计划,攻克JavaScript难关(React/Redux/ES6 etc.)
作者:余博伦链接:https://zhuanlan.zhihu.com/p/23412169来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 和大家一样,最近我也看了Jo ...
随机推荐
- mongodb(mongoose-redis-cache)
在传统的项目中,我们经常会用到缓存来优化数据库的读取,比如java中,我们利用spring的AOP能力,在读写数据库前增加对缓存的操作. 在node与mongodb的项目中也仍然会存在类似问题,本文参 ...
- 【WEB】初探Spring MVC框架
Spring MVC框架算是当下比较流行的Java开源框架.但实话实说,做了几年WEB项目,完全没有SpringMVC实战经验,乃至在某些交流场合下被同行严重鄙视“奥特曼”了.“心塞”的同时,只好默默 ...
- Web 数据存储总结
随着Web应用程序的出现,也产生了对于能够在客户端上存储用户信息能力的要求.这个问题的第一个解决方案是以cookie形似出现的.网景公司在一份名为“Persistent Client State: H ...
- Java对象序列化---转载
1.概念 序列化:把Java对象转换为字节序列的过程. 反序列化:把字节序列恢复为Java对象的过程. 2.用途 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个 ...
- 知方可补不足~用SqlProfiler来监视数据库死锁
回到目录 关于锁的相关知识,大家可以看我的这篇文章<知方可补不足~Sqlserver中的几把锁和.net中的事务级别> 死锁我想大家都知道,当一个对话(线程)占用一个资源时,别一个线程也同 ...
- java 线程的终止与线程中断
关于线程终止: 1.一般来讲线程在执行完毕后就会进入死亡状态,那该线程自然就终止了. 2.一些服务端的程序,可能在业务上需要,常驻系统.它本身是一个无穷的循环,用于提供服务.那对于这种线程我们该如何结 ...
- c#动态调用Webservices
方式一: Hashtable ht = new Hashtable(); ht.Add("a", "testhelloworld"); XmlDocument ...
- vuejs - the component is a fragment instance
vuejs - the component is a fragment instance http://vuejs.org/guide/components.html#Fragment-Instanc ...
- 关于BUG率的计算和它的实际意义的思考
我的微信号是Shalayang,以下是我的二维码名片,欢迎添加. 问题1:bug率有什么作用? my opion:用处有很多,需要具体情况具体分析,不过主要作用一般是来评价工作产品的质量.如果bug率 ...
- python入门学习课程推荐
最近在学习自动化,学习过程中,越来越发现coding能力的重要性,不会coding,基本不能开展自动化测试(自动化工具只是辅助). 故:痛定思痛,先花2个星期将python基础知识学习后,再进入自动化 ...