1
1
/** @jsx React.DOM */
2
2
var React = require ( 'react' ) ;
3
- var ReactRouter = require ( '../../modules/main' ) ;
4
- var Router = ReactRouter . Router ;
5
- var Route = ReactRouter . Route ;
6
- var Link = ReactRouter . Link ;
3
+ var Router = require ( '../../modules/main' ) ;
4
+ var Route = Router . Route ;
5
+ var Link = Router . Link ;
6
+
7
+ var api = 'http://addressbook-api.herokuapp.com/contacts' ;
8
+ var _contacts = { } ;
9
+ var _changeListeners = [ ] ;
10
+ var _initCalled = false ;
11
+
12
+ var ContactStore = {
13
+
14
+ init : function ( ) {
15
+ if ( _initCalled )
16
+ return ;
17
+
18
+ _initCalled = true ;
19
+
20
+ getJSON ( api , function ( err , res ) {
21
+ res . contacts . forEach ( function ( contact ) {
22
+ _contacts [ contact . id ] = contact ;
23
+ } ) ;
24
+
25
+ ContactStore . notifyChange ( ) ;
26
+ } ) ;
27
+ } ,
28
+
29
+ addContact : function ( contact , cb ) {
30
+ postJSON ( api , { contact : contact } , function ( res ) {
31
+ _contacts [ res . contact . id ] = res . contact ;
32
+ ContactStore . notifyChange ( ) ;
33
+ if ( cb ) cb ( res . contact ) ;
34
+ } ) ;
35
+ } ,
36
+
37
+ removeContact : function ( id , cb ) {
38
+ deleteJSON ( api + '/' + id , cb ) ;
39
+ delete _contacts [ id ] ;
40
+ ContactStore . notifyChange ( ) ;
41
+ } ,
42
+
43
+ getContacts : function ( ) {
44
+ var array = [ ] ;
45
+
46
+ for ( var id in _contacts )
47
+ array . push ( _contacts [ id ] ) ;
48
+
49
+ return array ;
50
+ } ,
51
+
52
+ getContact : function ( id ) {
53
+ return _contacts [ id ] ;
54
+ } ,
55
+
56
+ notifyChange : function ( ) {
57
+ _changeListeners . forEach ( function ( listener ) {
58
+ listener ( ) ;
59
+ } ) ;
60
+ } ,
61
+
62
+ addChangeListener : function ( listener ) {
63
+ _changeListeners . push ( listener ) ;
64
+ } ,
65
+
66
+ removeChangeListener : function ( listener ) {
67
+ _changeListeners = _changeListeners . filter ( function ( l ) {
68
+ return listener !== l ;
69
+ } ) ;
70
+ }
71
+
72
+ } ;
7
73
8
74
var App = React . createClass ( {
9
75
getInitialState : function ( ) {
10
76
return {
11
- contacts : [ ] ,
77
+ contacts : ContactStore . getContacts ( ) ,
12
78
loading : true
13
79
} ;
14
80
} ,
15
81
82
+ componentWillMount : function ( ) {
83
+ ContactStore . init ( ) ;
84
+ } ,
85
+
16
86
componentDidMount : function ( ) {
17
- store . getContacts ( function ( contacts ) {
18
- this . setState ( {
19
- contacts : contacts ,
20
- loading : false
21
- } ) ;
22
- } . bind ( this ) ) ;
87
+ console . log ( 'componentDidMount' )
88
+ ContactStore . addChangeListener ( this . updateContacts ) ;
89
+ } ,
90
+
91
+ componentWillUnmount : function ( ) {
92
+ console . log ( 'componentWillUnmount' )
93
+ ContactStore . removeChangeListener ( this . updateContacts ) ;
94
+ } ,
95
+
96
+ updateContacts : function ( contacts ) {
97
+ if ( ! this . isMounted ( ) )
98
+ return ;
99
+
100
+ this . setState ( {
101
+ contacts : ContactStore . getContacts ( ) ,
102
+ loading : false
103
+ } ) ;
23
104
} ,
24
105
25
106
indexTemplate : function ( ) {
@@ -50,29 +131,39 @@ var App = React.createClass({
50
131
var Contact = React . createClass ( {
51
132
getInitialState : function ( ) {
52
133
return {
53
- id : this . props . params . id ,
54
- avatar : 'http://placekitten.com/50/50' ,
55
- loading : true
134
+ contact : ContactStore . getContact ( this . props . params . id )
56
135
} ;
57
136
} ,
58
137
59
138
componentDidMount : function ( ) {
60
- store . getContact ( this . props . params . id , function ( contact ) {
61
- contact . loading = false ;
62
- this . setState ( contact ) ;
63
- } . bind ( this ) ) ;
139
+ ContactStore . addChangeListener ( this . updateContact ) ;
140
+ } ,
141
+
142
+ componentWillUnmount : function ( ) {
143
+ ContactStore . removeChangeListener ( this . updateContact ) ;
144
+ } ,
145
+
146
+ updateContact : function ( ) {
147
+ if ( ! this . isMounted ( ) )
148
+ return ;
149
+
150
+ this . setState ( {
151
+ contact : ContactStore . getContact ( this . props . params . id )
152
+ } ) ;
64
153
} ,
65
154
66
155
destroy : function ( ) {
67
- store . removeContact ( this . state . id ) ;
156
+ ContactStore . removeContact ( this . props . params . id ) ;
68
157
Router . transitionTo ( '/' ) ;
69
158
} ,
70
159
71
160
render : function ( ) {
72
- var name = this . state . first + ' ' + this . state . last ;
161
+ var contact = this . state . contact || { } ;
162
+ var name = contact . first + ' ' + contact . last ;
163
+ var avatar = contact . avatar || 'http://placekitten.com/50/50' ;
73
164
return (
74
165
< div className = "Contact" >
75
- < img height = "50" src = { this . state . avatar } />
166
+ < img height = "50" src = { avatar } />
76
167
< h3 > { name } </ h3 >
77
168
< button onClick = { this . destroy } > Delete</ button >
78
169
</ div >
@@ -83,12 +174,12 @@ var Contact = React.createClass({
83
174
var NewContact = React . createClass ( {
84
175
createContact : function ( event ) {
85
176
event . preventDefault ( ) ;
86
- store . addContact ( {
177
+ ContactStore . addContact ( {
87
178
first : this . refs . first . getDOMNode ( ) . value ,
88
179
last : this . refs . last . getDOMNode ( ) . value
89
180
} , function ( contact ) {
90
181
Router . transitionTo ( 'contact' , { id : contact . id } ) ;
91
- } . bind ( this ) ) ;
182
+ } ) ;
92
183
} ,
93
184
94
185
render : function ( ) {
@@ -112,69 +203,17 @@ var NotFound = React.createClass({
112
203
}
113
204
} ) ;
114
205
206
+ var routes = (
207
+ < Route handler = { App } >
208
+ < Route name = "new" path = "contact/new" handler = { NewContact } />
209
+ < Route name = "not-found" path = "contact/not-found" handler = { NotFound } />
210
+ < Route name = "contact" path = "contact/:id" handler = { Contact } />
211
+ </ Route >
212
+ ) ;
115
213
116
- // data store stuff ...
117
-
118
- var api = 'http://addressbook-api.herokuapp.com/contacts' ;
119
-
120
- var store = {
121
- contacts : {
122
- loaded : false ,
123
- map : { } ,
124
- records : [ ]
125
- } ,
126
-
127
- getContacts : function ( cb ) {
128
- if ( store . contacts . loaded ) {
129
- if ( cb ) cb ( store . contacts . records ) ;
130
- } else {
131
- getJSON ( api , function ( err , res ) {
132
- var contacts = res . contacts ;
133
- store . contacts . loaded = true ;
134
- store . contacts . records = contacts ;
135
- store . contacts . map = contacts . reduce ( function ( map , contact ) {
136
- map [ contact . id ] = contact ;
137
- return map ;
138
- } , { } ) ;
139
- if ( cb ) cb ( contacts ) ;
140
- } ) ;
141
- }
142
- } ,
143
-
144
- getContact : function ( id , cb ) {
145
- var contact = store . contacts . map [ id ] ;
146
- if ( contact ) {
147
- if ( cb ) cb ( contact ) ;
148
- } else {
149
- var url = api + '/' + id ;
150
- getJSON ( url , function ( err , res ) {
151
- if ( err ) {
152
- return Router . replaceWith ( 'not-found' ) ;
153
- }
154
- var contact = res . contact ;
155
- store . contacts . map [ contact . id ] = contact ;
156
- if ( cb ) cb ( contact ) ;
157
- } ) ;
158
- }
159
- } ,
160
-
161
- addContact : function ( contact , cb ) {
162
- postJSON ( api , { contact : contact } , function ( res ) {
163
- var savedContact = res . contact ;
164
- store . contacts . records . push ( savedContact ) ;
165
- store . contacts . map [ contact . id ] = savedContact ;
166
- if ( cb ) cb ( savedContact ) ;
167
- } ) ;
168
- } ,
214
+ React . renderComponent ( routes , document . body ) ;
169
215
170
- removeContact : function ( id , cb ) {
171
- var contact = store . contacts . map [ id ] ;
172
- delete store . contacts . map [ id ] ;
173
- var index = store . contacts . records . indexOf ( contact ) ;
174
- store . contacts . records . splice ( index , 1 ) ;
175
- deleteJSON ( api + '/' + id , cb ) ;
176
- }
177
- } ;
216
+ // Request utils.
178
217
179
218
function getJSON ( url , cb ) {
180
219
var req = new XMLHttpRequest ( ) ;
@@ -205,13 +244,3 @@ function deleteJSON(url, cb) {
205
244
req . open ( 'DELETE' , url ) ;
206
245
req . send ( ) ;
207
246
}
208
-
209
-
210
- Router (
211
- < Route handler = { App } >
212
- < Route name = "new" path = "contact/new" handler = { NewContact } />
213
- < Route name = "not-found" path = "contact/not-found" handler = { NotFound } />
214
- < Route name = "contact" path = "contact/:id" handler = { Contact } />
215
- </ Route >
216
- ) . renderComponent ( document . body ) ;
217
-
0 commit comments