Skip to content

Commit 6144412

Browse files
committed
refactor using lens
1 parent e42cfd9 commit 6144412

File tree

7 files changed

+145
-80
lines changed

7 files changed

+145
-80
lines changed

examples/todomvc/package.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
".js"
1414
]
1515
}
16-
]
16+
],
17+
"envify"
1718
]
1819
},
1920
"scripts": {
@@ -23,7 +24,11 @@
2324
"test": "jest"
2425
},
2526
"jest": {
26-
"moduleFileExtensions": ["js", "jsx", "es6"]
27+
"moduleFileExtensions": [
28+
"js",
29+
"jsx",
30+
"es6"
31+
]
2732
},
2833
"dependencies": {
2934
"classnames": "^2.2.0",
@@ -36,8 +41,6 @@
3641
"union-type": "^0.3.3"
3742
},
3843
"devDependencies": {
39-
"react-addons-test-utils": "^15.3.2",
40-
"jest-cli": "^16.0.2",
4144
"babel": "^6.5.2",
4245
"babel-jest": "^16.0.0",
4346
"babel-plugin-lodash": "^2.0.1",
@@ -46,7 +49,10 @@
4649
"babelify": "^7.2.0",
4750
"browserify": "^12.0.1",
4851
"ecstatic": "^1.3.1",
52+
"envify": "^3.4.1",
4953
"jest-cli": "^0.7.0",
54+
"ramda": "^0.22.1",
55+
"react-addons-test-utils": "^15.3.2",
5056
"uglify-js": "^2.6.1",
5157
"watchify": "^3.6.1"
5258
},

examples/todomvc/src/components/Footer.jsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ import React from 'react'
22
import classnames from 'classnames'
33
import {connect} from 'react-most'
44
import MainSection from './MainSection'
5+
import Intent from '../todo.action.js'
56
const FILTER_TITLES = {
67
'SHOW_ALL': 'All',
78
'SHOW_ACTIVE': 'Active',
89
'SHOW_COMPLETED': 'Completed'
910
}
1011

11-
const FILTER_FUNC = {
12+
export const FILTER_FUNC = {
1213
'SHOW_ALL': _=>_,
13-
'SHOW_ACTIVE': todos=>todos.filter(todo=>!todo.done),
14-
'SHOW_COMPLETED': todos=>todos.filter(todo=>todo.done),
14+
'SHOW_ACTIVE': todos=>todos.filter(todo=>!todo.completed),
15+
'SHOW_COMPLETED': todos=>todos.filter(todo=>todo.completed),
1516
}
1617
let Footer = React.createClass({
1718
renderTodoCount() {
@@ -68,7 +69,7 @@ let Footer = React.createClass({
6869

6970
export default connect((intent$)=>{
7071
return {
71-
clear: ()=>({type:'clear'}),
72-
filterWith: filter=>({type:'filter', filter}),
72+
clear: Intent.Clear,
73+
filterWith: Intent.Filter,
7374
}
7475
})(Footer)

examples/todomvc/src/components/MainSection.jsx

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,68 +6,68 @@ import rest from 'rest'
66
const remote = 'todos.json';
77
import * as most from 'most'
88
import Intent from '../todo.action'
9-
const id = _=>_
10-
const anyToId = ()=>id
9+
import r from 'ramda'
10+
const anyToId = ()=>r.identity
1111

1212
const MainSection = ({todos,filter}) => {
1313
const completedCount = todos.reduce((count, todo) => todo.done ? count + 1 : count, 0);
14-
1514
const filteredTodos = filter(todos);
1615
return (
17-
<section className="main">
18-
<ul className="todo-list">
19-
{filteredTodos.map(todo =>
20-
<TodoItem key={todo.id} todo={todo} />
21-
)}
22-
</ul>
23-
<Footer completedCount={completedCount} activeCount={todos.length-completedCount} />
24-
</section>
16+
<section className="main">
17+
<ul className="todo-list">
18+
{filteredTodos.map((todo,index) =>
19+
<TodoItem key={todo.id} index={index} todo={todo} />
20+
)}
21+
</ul>
22+
<Footer completedCount={completedCount} activeCount={todos.length-completedCount} />
23+
</section>
2524
)
2625
}
2726

2827
MainSection.defaultProps = {
2928
todos: [
30-
{id:0, text:'Loading...dadada', done:false},
29+
{id:0, text:'Loading...dadada', completed:false},
3130
],
3231
filter: _=>_
3332
}
3433

3534
export default connect((intent$)=>{
36-
let editSink$ = intent$.map(Intent.case({
37-
Edit: todo => state => ({
38-
todos: state.todos.map(oldtodo=>todo.id==oldtodo.id?todo:oldtodo)
39-
}),
35+
let lensTodos = r.lensProp('todos')
36+
let lensComplete = r.lensProp('completed')
37+
let lensTodo = index => r.compose(lensTodos, r.lensIndex(index))
38+
let lensTodoComplete = index => r.compose(lensTodo(index), lensComplete)
39+
let sinks$ = intent$.map(Intent.case({
40+
Edit: (todo,index) => r.set(lensTodo(index), todo),
41+
Clear: () => r.over(lensTodos, r.filter(todo=>todo.completed)),
42+
Delete: id => r.over(lensTodos, r.filter(todo=>todo.id!=id)),
43+
Filter: filter=>state=>({ filter }),
44+
Done: index=>r.over(lensTodoComplete(index), r.not),
4045
_:anyToId
41-
}));
42-
let dataSink$ = most.fromPromise(rest(remote))
43-
.map(x=>JSON.parse(x.entity))
44-
.map(data=>()=>({todos: data}));
45-
46-
let clearSink$ = intent$.map(Intent.case({
47-
Clear: () => state=>({
48-
todos: state.todos.filter(todo=>{
49-
return !todo.completed
50-
})
51-
}),
52-
_: anyToId
5346
}))
47+
let data$ = most.fromPromise(rest(remote))
48+
.map(x=>JSON.parse(x.entity))
49+
.map(data=>()=>({todos: data}));
5450

55-
/* let searchSource$ = intent$.filter(i=>i.type=='search').debounce(500).map(x=>x.text.trim());
56-
57-
* let blankSearchSink$ = searchSource$.filter(search=>!search).map(_=>_=>({filter:_.identity}));
58-
* let searchSink$ = searchSource$.filter(search=>!!search).map(search=>state=>({
59-
* filter: x=>x.filter(todo=>{
60-
* return !!search.toLowerCase().split(' ').filter((word)=>{
61-
* return !!todo.text.toLowerCase().split(' ').filter(w=>w==word).length
62-
* }).length
63-
* })}));
51+
let searchSink$ = intent$
52+
.filter(Intent.case({
53+
Search: x=>!!x,
54+
_:()=>false
55+
}))
56+
.debounce(500)
57+
.map(Intent.case({
58+
Search: x=>x.text.trim()
59+
}))
60+
.map(search=>state=>({
61+
filter: x=>x.filter(todo=>{
62+
return !!search.toLowerCase().split(' ').filter((word)=>{
63+
return !!todo.text.toLowerCase().split(' ').filter(w=>w==word).length
64+
}).length
65+
})
66+
}))
6467

65-
* let filterSink$ = intent$.filter(x=>x.type=='filter').map(intent=>state=>({
66-
* filter: intent.filter
67-
* }));*/
6868
return {
69-
editSink$,
70-
dataSink$,
71-
clearSink$,
69+
sinks$,
70+
searchSink$,
71+
data$,
7272
}
7373
})(MainSection)

examples/todomvc/src/components/TodoItem.jsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import TodoTextInput from './TodoTextInput'
44
import MainSection from './MainSection'
55
import {connect} from 'react-most'
66
import Intent from '../todo.action'
7-
const TodoItemView = ({todo, actions}) => {
7+
const TodoItemView = ({todo, actions, index}) => {
88
return <div className="view">
99
<input className="toggle"
1010
type="checkbox"
11-
checked={todo.done}
12-
onChange={()=>actions.done(todo.id)} />
11+
checked={todo.completed}
12+
onChange={()=>actions.done(index)} />
1313
<label onDoubleClick={()=>actions.editing(todo.id)}>
1414
{todo.text}
1515
</label>
@@ -19,16 +19,17 @@ const TodoItemView = ({todo, actions}) => {
1919
}
2020

2121
const TodoItem = props => {
22-
const { todo, actions, editing } = props
22+
const { todo, actions, editing, index} = props
2323
const {edit} = actions
2424
let element = editing === todo.id ? <TodoTextInput text={todo.text}
2525
itemid={todo.id}
2626
editing={editing === todo.id}
2727
actions={actions}
28-
/>: <TodoItemView todo={todo} actions={actions}/>
28+
index={index}
29+
/>: <TodoItemView index={index} todo={todo} actions={actions}/>
2930

3031
return <li className={classnames({
31-
completed: todo.done,
32+
completed: todo.completed,
3233
editing: editing===todo.id
3334
})}>{element}</li>
3435
}

examples/todomvc/src/components/TodoTextInput.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import classnames from 'classnames'
33
import MainSection from './MainSection'
44
import {connect} from 'react-most'
55
import TodoItem from './TodoItem'
6+
67
let TodoTextInput = React.createClass({
78
getInitialState(){
89
return {
@@ -30,7 +31,7 @@ let TodoTextInput = React.createClass({
3031

3132
handleBlur(e) {
3233
if (!this.props.newTodo) {
33-
this.props.actions.edit({id:this.props.itemid,text:e.target.value});
34+
this.props.actions.edit({id:this.props.itemid,text:e.target.value}, this.props.index);
3435
this.props.actions.editing(-1);
3536
}
3637
},

examples/todomvc/src/todo.action.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import Type from 'union-type'
33
export default Type({
44
Add: [Object],
55
Delete: [Number],
6-
Edit: [Object],
6+
Edit: [Object, Number],
77
Editing: [Number],
88
Clear: [],
9+
Filter: [Function],
910
Done: [Number],
1011
Complete: [Number],
1112
Search: [String],
@@ -30,16 +31,3 @@ export function deleteTodo(intent$){
3031
})
3132
))
3233
}
33-
export function completeTodo(intent$){
34-
return intent$.filter(x=>x.type=='done')
35-
.map(intent=>(
36-
state=>({
37-
todos: state.todos.map(todo=>{
38-
if(todo.id==intent.id){
39-
todo.done =! todo.done;
40-
return todo;
41-
}
42-
return todo;
43-
})
44-
})))
45-
}

0 commit comments

Comments
 (0)