昨日の#jxugではAndroid(けっきょくC#じゃなくてJavaで)とMilkcocoaをつなげてみてました。
React入門者向けハンズオンで作ってみました。ハンズオンで使ったCreate React Appも参考にしてます。
es2015な感じで書いたので誰かレビューしてほしい...
ちなみに1年前にこんな記事も書いてたらしいですがすっかり忘れてました。あのときはFluxxorが流行ってた記憶があります。
milkcocoa
IoTのバックエンドサービスとして使われているリアルタイム通信サポートのバックエンドサービス https://mlkcca.com/
今回はチャットの裏側に使います。
公式チュートリアルをいじってReactでチャットを作ってみた
まずは完成品
URL: https://private-chipmunk-54046.netlify.com/
(いつまで稼働させてるかはわからないです)
リアルタイムなチャットができます。
参考にしたチュートリアル
このチュートリアルをやるとマークダウン対応のコメント欄みたいなものをつくれます。
メインのソースコードはGitHub上のexample.js
です。
https://github.com/reactjs/react-tutorial/blob/master/public/scripts/example.js
書いたソースコード
先ほどのexample.js
をもとに書き換えてます。
const milkcocoa = new MilkCocoa('your-app-id.mlkcca.com');
const ds = milkcocoa.dataStore('react-chat');
//CommentBox -> CommentList -> Comment
class Comment extends React.Component {
constructor(props) {
super(props);
};
rawMarkup(){
let md = new Remarkable();
let rawMarkup = md.render(this.props.children.toString());
return { __html: rawMarkup };
};
render() {
let md = new Remarkable();
return (
<div className="comment">
<h2 className="commentAuthor">{this.props.author}</h2>
<span dangerouslySetInnerHTML={this.rawMarkup()} />
</div>
);
};
};
//CommentBox->CommentList
class CommentList extends React.Component {
render() {
let commentNodes = this.props.data.map( (item) => {
let comment = item.value;
return (
<Comment author={comment.author} key={item.id}>
{comment.text}
</Comment>
);
});
return (
<div className="commentList">{commentNodes}</div>
);
};
};
//CommentBox->CommentForm
class CommentForm extends React.Component {
constructor(props) {
super(props);
this.state = {author: '', text: ''};
};
handleAuthorChange (e) {
this.setState({author: e.target.value});
};
handleTextChange (e) {
this.setState({text: e.target.value});
};
handleSubmit (e) {
e.preventDefault();
let author = this.state.author.trim();
let text = this.state.text.trim();
if (!text || !author) return;
this.props.onCommentSubmit({author: author, text: text});
// this.setState({author: '', text: ''});
this.setState({text: ''}); //名前は残す
};
render() {
return (
<form className="commentForm" onSubmit={this.handleSubmit.bind(this)}>
<input
type="text"
placeholder="名前を入力してね。"
value={this.state.author}
onChange={this.handleAuthorChange.bind(this)}
/>
<input
type="text"
placeholder="マークダウン使えるよ"
value={this.state.text}
onChange={this.handleTextChange.bind(this)}
/>
<input type="submit" value="Post" />
</form>
);
};
};
//CommentBox
class CommentBox extends React.Component {
constructor(props) {
super(props);
this.state = {data: []};
};
componentDidMount () {
this.loadCommentsFromServer();
ds.on('push', this.loadCommentsFromServer.bind(this));
};
loadCommentsFromServer () {
let history = ds.history();
history.on('data', (data) => {
this.setState({data: data});
});
history.run();
};
handleCommentSubmit (comment) {
ds.push(comment);
};
render() {
return (
<div className="commentBox">
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
<CommentList data={this.state.data} />
</div>
);
};
};
class App extends React.Component {
render(){
return(
<div className="App">
<div className="App-header">
<img src="../logo.svg" className="App-logo" alt="logo" />
<h1>Milkcocoa+Reactでリアルタイムチャット</h1>
</div>
<CommentBox />
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('content')
);
コメントないけど自分用メモなつもりなのであしからず。
ES5 -> ES2015書き換え
参考にしたチュートリアルはES5ベースの書き方になっているのでES2015な書き方に変更します。
これらを参考にしてReact.createClass()
をReact.Component
に書き換えました。
主にこの辺りで若干手こずりました。
- getInitialState()が使えないのでconstructorで初期化
getInitialState: function() {
return {author: '', text: ''};
},
↓ stateの初期化の仕方が変わる
constructor(props) {
super(props);
this.state = {author: '', text: ''};
};
- thisのオートバインディングがなくなるので自分でバインドする
<form className="commentForm" onSubmit={this.handleSubmit}>
↓ ここもバインドしてあげる
<form className="commentForm" onSubmit={this.handleSubmit.bind(this)}>
みたいな書き方に変更します。
Milkcocoa的な部分
CommentBoxのコンポーネント内のメソッドで処理してます。
- handleCommentSubmit内でデータ保存 / pushメソッド
MilkcocoaのpushメソッドをhandleCommentSubmit()で行ってます。
handleCommentSubmit (comment) {
ds.push(comment);
};
pushメソッドが実行されると接続してるクライアントにpushイベントが発火されます。
- loadCommentsFromsSever内でデータ取得 / historyメソッド
loadCommentsFromServer () {
let history = ds.history();
history.on('data', (data) => {
this.setState({data: data});
});
history.run();
};
- historyメソッドの初期呼び出しとpushイベントの監視 / onメソッド
今日のハンズオン資料にあるようにcomponentDidMountはコンポーネントがレンダリングされた後に一度だけ呼ばれます。
なのでそのタイミングでhistoryを発火させる(初期ロード)のと、onメソッドでpushイベントを監視を開始します。
これで他の人がコメントするたびにhistoryが実行されてデータが更新されてリアルタイムチャットになります。
componentDidMount () {
this.loadCommentsFromServer();
ds.on('push', this.loadCommentsFromServer.bind(this));
};
雑感
ハンズオン中につくったので雑かもしれないですが取りあえずまとめてみました。
久しぶりにReact触ったけど、バージョンアップによって書き方が変わっててどれを参考にするのがいいのかってちゃんと動きを追ってないと大変そうだなぁという印象でした苦笑
でもとりあえずリハビリな感じになって楽しかった!