Skip to content

Instantly share code, notes, and snippets.

@onionmk2
Created September 14, 2016 14:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save onionmk2/093ab2822ec7f0494a75a79fbfe8e229 to your computer and use it in GitHub Desktop.
Save onionmk2/093ab2822ec7f0494a75a79fbfe8e229 to your computer and use it in GitHub Desktop.
react_tutorial_client.jsx
const DOMPurify = require('dompurify');
const React = require('react');
const ReactDOM = require('react-dom');
const Remarkable = require('remarkable');
const Comment = React.createClass({
propTypes: {
author: React.PropTypes.string.isRequired,
children: React.PropTypes.string.isRequired,
},
render() {
function createMarkup(dirty) {
const md = new Remarkable();
const parsedComment = md.render(dirty);
const sanitizedComment = DOMPurify.sanitize(parsedComment);
return { __html: sanitizedComment };
}
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHTML={createMarkup(this.props.children)} />
</div>
);
},
});
const CommentList = React.createClass({
render() {
const commentNodes = this.props.data.map(function (item, index) {
return (
<Comment author={item.author} key={index}>
{item.text}
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
},
});
const CommentForm = React.createClass({
getInitialState() {
return ({
author: '',
text: '',
});
},
componentWillUnmount() {
if (this.xhr) {
this.xhr.abort();
}
},
/*
* renderは pureであるべきなのでsetStateしてはいけない
* setStateするメソッドをコールバックに「登録する」のはrenderでやってOK
*/
handleSubmitForm(e) {
e.preventDefault();
(function trimComments() {
this.setState({
author: this.state.author.trim(),
text: this.state.text.trim(),
});
}).bind(this);
(function optimisticUpdate() {
this.props.addCommentToState({ author: this.state.author, text: this.state.text });
}).bind(this);
(function postComments() {
this.xhr = new XMLHttpRequest();
this.xhr.open('POST', 'http://localhost:3000/api/comments', true);
this.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
const payload = JSON.stringify({ author: this.state.author, text: this.state.text });
this.xhr.send(payload);
}).bind(this)();
(function clearComments() {
this.setState({ author: '' });
this.setState({ text: '' });
}).bind(this)();
},
handleAuthorChange(e) {
this.setState({ author: e.currentTarget.value });
},
handleTextChange(e) {
this.setState({ text: e.currentTarget.value });
},
render() {
return (
<form className="commentForm" onSubmit={this.handleSubmitForm}>
<input type="text" placeholder="YourName" value={this.state.author} onChange={this.handleAuthorChange} />
<input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange} />
<input type="submit" value="submit" />
</form>
);
},
});
const CommentBox = React.createClass({
addCommentsToState(newComment) {
const comments = this.state.data.slice();
comments.push(newComment);
this.setState({ data: comments });
},
/*
InitialStateがないと、<CommentList data={this.state.data}/>が
Uncaught TypeError: Cannot read property 'data' of nullで死ぬ。
*/
getInitialState() {
return ({ data: [] });
},
componentDidMount() {
const loadCommentsFromServer = () => {
this.xhr = new XMLHttpRequest();
this.xhr.open('GET', 'http://localhost:3000/api/comments', true);
this.xhr.onload = () => {
if (this.xhr.status === 200) {
const commentData = JSON.parse(this.xhr.response);
this.setState({ data: commentData });
} else {
console.log(`xhr.status ${this.xhr.status}`);
}
};
this.xhr.send();
};
/*
1回即呼び出ししないと、pollIntervalが長いときにAJAX前の状態がユーザーに見えてしまう。
*/
loadCommentsFromServer();
setInterval(loadCommentsFromServer, this.props.pollInterval);
},
componentWillUnmount() {
this.xhr.abort();
},
render() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm addCommentToState={this.addCommentsToState.bind(this)} />
</div>
);
},
});
ReactDOM.render(<CommentBox pollInterval={10000} />, document.getElementById('content'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment