Skip to content

Commit 930d78b

Browse files
committed
completed tutorial
completed tutorial with comments added
1 parent 64a6dfc commit 930d78b

File tree

3 files changed

+320
-6
lines changed

3 files changed

+320
-6
lines changed

comments.json

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
11
[
22
{
33
"id": 1388534400000,
4-
"author": "Pete Hunt",
4+
"author": "Pete Bunt",
55
"text": "Hey there!"
66
},
77
{
88
"id": 1420070400000,
99
"author": "Paul O’Shannessy",
1010
"text": "React is *great*!"
11+
},
12+
{
13+
"id": 1466069074518,
14+
"author": "JSKY",
15+
"text": "hello world"
16+
},
17+
{
18+
"id": 1466069113691,
19+
"author": "scarlet pimpernel",
20+
"text": "too late"
21+
},
22+
{
23+
"id": 1466090323155,
24+
"author": "joe shmoe",
25+
"text": "this music smells bad"
26+
},
27+
{
28+
"id": 1466090425597,
29+
"author": "terrible optimiser",
30+
"text": "a really long comment,a really long comment,a really long comment,a really long comment,a really long comment,a really long comment,a really long comment,a really long comment,a really long comment,a really long comment,a really long comment,a really long comment"
31+
},
32+
{
33+
"id": 1466090818720,
34+
"author": "quick",
35+
"text": "optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic v v optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic v v v optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic optimistic optimistic optimistic optimistic v optimistic optimistic optimistic optimistic"
1136
}
1237
]

public/index.html

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@
1313
</head>
1414
<body>
1515
<div id="content"></div>
16-
<script type="text/babel" src="scripts/example.js"></script>
17-
<script type="text/babel">
18-
// To get started with this tutorial running your own code, simply remove
19-
// the script tag loading scripts/example.js and start writing code here.
20-
</script>
16+
<!-- <script type="text/babel" src="scripts/example.js"></script> -->
17+
<script type="text/babel" src="scripts/comments.js"></script>
2118
</body>
2219
</html>

public/scripts/comments.js

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
2+
// hardcoded dummy json data
3+
var data = [
4+
{id: 1, author: "Pete Cunt", text: "This is one comment"},
5+
{id: 2, author: "Jordan Walke", text: "This is *another* comment"}
6+
];
7+
8+
9+
10+
// the commentList component using property data passed down from parent CommentBox
11+
var CommentList = React.createClass({
12+
render: function() {
13+
var commentNodes = this.props.data.map(function(comment) {
14+
return (
15+
<Comment author={comment.author} key={comment.id}>
16+
{comment.text}
17+
</Comment>
18+
);
19+
});
20+
return (
21+
<div className="commentList">
22+
{commentNodes}
23+
</div>
24+
);
25+
}
26+
});
27+
28+
29+
// the commentList component using raw data.
30+
// var CommentList = React.createClass({
31+
// render: function() {
32+
// return (
33+
// <div className="commentList">
34+
// <Comment author="Pete Hunt">This is one comment</Comment>
35+
// <Comment author="Jordan Walke">This is *another* comment</Comment>
36+
// </div>
37+
// );
38+
// }
39+
// });
40+
41+
42+
// note: With the traditional DOM, input elements are rendered and the browser
43+
// manages the state (its rendered value). As a result, the state of the actual DOM
44+
// will differ from that of the component which is not what we want.
45+
// In React, components should always represent the state of the view
46+
// and not only at the point of initialization.
47+
// Hence, we use this.state to save the user's input as it is entered.
48+
// We define an initial state with two properties author and text and set them to be empty strings.
49+
// In our <input> elements, we set the value prop to reflect the state of the component
50+
// and attach onChange handlers to them.
51+
// These <input> elements with a value set are called controlled components.
52+
// Read more about controlled components here:
53+
// https://facebook.github.io/react/docs/forms.html#controlled-components
54+
55+
var CommentForm = React.createClass({
56+
getInitialState: function() {
57+
return {author: '', text: ''};
58+
},
59+
handleAuthorChange: function(e) {
60+
this.setState({author: e.target.value});
61+
},
62+
handleTextChange: function(e) {
63+
this.setState({text: e.target.value});
64+
},
65+
// clears the form fields when the form is submitted with valid input.
66+
handleSubmit: function(e) {
67+
e.preventDefault();
68+
var author = this.state.author.trim();
69+
var text = this.state.text.trim();
70+
if (!text || !author) {
71+
return;
72+
}
73+
this.props.onCommentSubmit({author: author, text: text});
74+
this.setState({author: '', text: ''});
75+
},
76+
render: function() {
77+
return (
78+
<form className="commentForm" onSubmit={this.handleSubmit}>
79+
<input
80+
type="text"
81+
placeholder="Your name"
82+
value={this.state.author}
83+
onChange={this.handleAuthorChange}
84+
/>
85+
<input
86+
type="text"
87+
placeholder="Say something..."
88+
value={this.state.text}
89+
onChange={this.handleTextChange}
90+
/>
91+
<input type="submit" value="Post" />
92+
</form>
93+
);
94+
}
95+
});
96+
97+
// // the comment form component with http post
98+
// var CommentForm = React.createClass({
99+
// render: function() {
100+
// return (
101+
// <form className="commentForm">
102+
// <input type="text" placeholder="Your name" />
103+
// <input type="text" placeholder="Say something..." />
104+
// <input type="submit" value="Post" />
105+
// </form>
106+
// );
107+
// }
108+
// });
109+
110+
// the comment form component dummy
111+
// var CommentForm = React.createClass({
112+
// render: function() {
113+
// return (
114+
// <div className="commentForm">
115+
// Hello, world! I am a CommentForm.
116+
// </div>
117+
// );
118+
// }
119+
// });
120+
121+
// load the list and form components.
122+
// tutorial1.js
123+
// var CommentBox = React.createClass({
124+
// render: function() {
125+
// return (
126+
// <div className="commentBox">
127+
// <h1>Comments</h1>
128+
// <CommentList />
129+
// <CommentForm />
130+
// </div>
131+
// );
132+
// }
133+
// });
134+
135+
// load the list and form components with property data that was loaded in on render.
136+
var CommentBox = React.createClass({
137+
// sofar comments have been mutable, now we give them state, loaded into an array
138+
getInitialState: function() {
139+
return {data: []};
140+
},
141+
// send asynch ajax request for the fresh state of the comment data
142+
// replaces old initial state with new state from server
143+
loadCommentsFromServer: function() {
144+
$.ajax({
145+
url: this.props.url,
146+
dataType: 'json',
147+
cache: false,
148+
success: function(data) {
149+
this.setState({data: data});
150+
}.bind(this),
151+
error: function(xhr, status, err) {
152+
console.error(this.props.url, status, err.toString());
153+
}.bind(this)
154+
});
155+
},
156+
// poll the server for new data.
157+
componentDidMount: function() {
158+
this.loadCommentsFromServer();
159+
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
160+
},
161+
// handle comments that are submitted via the form component
162+
// When a user submits a comment, we will need to refresh the list of comments
163+
// to include the new one. It makes sense to do all of this logic in CommentBox
164+
// since CommentBox owns the state that represents the list of comments.
165+
// We need to pass data from the child component back up to its parent.
166+
// We do this by passing a callback (handleCommentSubmit) from the parent's
167+
// render method, into the child, which binds it to the child's onCommentSubmit event.
168+
// CommentBox has made the callback available to CommentForm via the onCommentSubmit prop,
169+
// the CommentForm can call the callback when the user submits the form.
170+
// Whenever the event is triggered, the callback will be invoked.
171+
172+
// the submit callback function
173+
handleCommentSubmit: function(comment) {
174+
// instead of waiting for the request to complete before the submitted
175+
// comment appears in the list. We can optimistically add this comment to
176+
// the list before sending to the server to make the app feel faster.
177+
178+
// the current state of the comments
179+
var comments = this.state.data;
180+
// Optimistically set an id on the new comment. It will be replaced by an
181+
// id generated by the server. In a production application you would likely
182+
// not use Date.now() for this and would have a more robust system in place.
183+
comment.id = Date.now();
184+
var newComments = comments.concat([comment]);
185+
this.setState({data: newComments});
186+
187+
// submit to the server and refresh the list
188+
$.ajax({
189+
url: this.props.url,
190+
dataType: 'json',
191+
type: 'POST',
192+
data: comment,
193+
success: function(data) {
194+
this.setState({data: data});
195+
}.bind(this),
196+
error: function(xhr, status, err) {
197+
this.setState({data: comments});
198+
console.error(this.props.url, status, err.toString());
199+
}.bind(this)
200+
});
201+
},
202+
render: function() {
203+
return (
204+
<div className="commentBox">
205+
<h1>Comments</h1>
206+
<CommentList data={this.state.data} />
207+
{/*callback is passed to form component on the onCommentSubmit event */}
208+
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
209+
{/*<CommentList data={this.props.data} />*/}
210+
{/*<CommentForm />*/}
211+
</div>
212+
);
213+
}
214+
});
215+
216+
// define the comment component (without remarkable markups)
217+
// var Comment = React.createClass({
218+
// render: function() {
219+
// return (
220+
// <div className="comment">
221+
// <h2 className="commentAuthor">
222+
// {this.props.author}
223+
// </h2>
224+
// {this.props.children}
225+
// </div>
226+
// );
227+
// }
228+
// });
229+
230+
// define the comment (with remarkable markups), but tags will show due to React.
231+
// var Comment = React.createClass({
232+
// render: function() {
233+
// var md = new Remarkable();
234+
// return (
235+
// <div className="comment">
236+
// <h2 className="commentAuthor">
237+
// {this.props.author}
238+
// </h2>
239+
// {md.render(this.props.children.toString())}
240+
// </div>
241+
// );
242+
// }
243+
// });
244+
245+
// for the Remarkeable markup to work,
246+
// we need to tell it to ignore Reacts default XSS guarding.
247+
// were relying on remarkable to be secure.
248+
// it is, remarkable automatically strips HTML markup and insecure links from the output.
249+
// tutorial7.js
250+
var Comment = React.createClass({
251+
rawMarkup: function() {
252+
var md = new Remarkable();
253+
var rawMarkup = md.render(this.props.children.toString());
254+
return { __html: rawMarkup };
255+
},
256+
257+
render: function() {
258+
return (
259+
<div className="comment">
260+
<h2 className="commentAuthor">
261+
{this.props.author}
262+
</h2>
263+
<span dangerouslySetInnerHTML={this.rawMarkup()} />
264+
</div>
265+
);
266+
}
267+
});
268+
269+
270+
271+
// instead of using jsx tags we could also use raw js, but its more work
272+
// var CommentBox = React.createClass({displayName: 'CommentBox',
273+
// render: function() {
274+
// return (
275+
// React.createElement('div', {className: "commentBox"},
276+
// "Hello, world! I am a CommentBox."
277+
// )
278+
// );
279+
// }
280+
// });
281+
282+
// The render method always needs to be loaded last. it renders the main DOM node.
283+
// here we create a CommentBox and render it as Reacts root node.
284+
ReactDOM.render(
285+
// passing in hardcoded json data as a property
286+
// <CommentBox data={data} />,
287+
// passing in server endpoint and polling interval as properties
288+
<CommentBox url="/api/comments" pollInterval={2000} />,
289+
// <CommentBox url="/api/comments" />,
290+
// React.createElement(CommentBox, null),
291+
document.getElementById('content')
292+
);

0 commit comments

Comments
 (0)