Step6: メモの更新機能を追加しよう!
このステップではMeteorコレクションの更新方法について学びます。
メモのテキストエリア化
現在の状態でもメモの編集はできますが、ブラウザをリロードすると元に戻ってしまいます。また複数クライアント間で同期されません。テキストエリアのchange
イベントを検知してMemosコレクションを更新するように設定してみましょう。
AppContainerにメモ更新用のfucntion updateMemoContent()
を追加します。
imports/ui/components/containers/AppContainer.js
import AppLayout from '../layouts/AppLayout';
import { Memos } from '../../api/memos/memos';
import { createContainer } from 'meteor/react-meteor-data';
const createMemo = content => {
Memos.insert({content});
};
const removeMemo = memoId => {
Memos.remove({_id: memoId});
};
const updateMemoContent = (memoId, content) => {
Memos.update({_id: memoId}, {$set: {content}});
};
export default createContainer(() => {
return {
memos: Memos.find({}, {sort: {createdAt: -1}}).fetch(),
createMemo,
removeMemo,
updateMemoContent,
};
}, AppLayout);
AppLayout->MemoList->MemoItemの順でMemoItemのpropsに渡します。
imports/ui/layouts/AppLayout.js
import React from 'react';
import Header from '../components/Header';
import MemoList from '../components/MemoList';
export default class AppLayout extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
const { memos, createMemo } = this.props;
createMemo(`New memo ${memos.length + 1}`);
}
render() {
const { memos, removeMemo, updateMemoContent } = this.props;
return (
<div className="container">
<Header />
<button className="add-button" onClick={this.onClick}>Add</button>
<MemoList
memos={memos}
removeMemo={removeMemo}
updateMemoContent={updateMemoContent}
/>
</div>
);
}
}
AppLayout.propTypes = {
memos: React.PropTypes.array.isRequired,
createMemo: React.PropTypes.func.isRequired,
removeMemo: React.PropTypes.func.isRequired,
updateMemoContent: React.PropTypes.func.isRequired,
};
imports/ui/components/MemoList.js
import React from 'react';
import MemoItem from './MemoItem';
export default class MemoList extends React.Component {
render() {
const { memos, removeMemo, updateMemoContent } = this.props;
return (
<div className="memo-list">
{memos.map(memo => (
<MemoItem
key={memo._id}
memo={memo}
removeMemo={removeMemo}
updateMemoContent={updateMemoContent}
/>
))}
</div>
);
}
}
MemoList.propTypes = {
memos: React.PropTypes.array.isRequired,
removeMemo: React.PropTypes.func.isRequired,
updateMemoContent: React.PropTypes.func.isRequired,
};
imports/ui/components/MemoItem.js
import React from 'react';
export default class MemoItem extends React.Component {
constructor(props) {
super(props);
const { memo } = this.props;
this.state = {
textAreaValue: memo.content
};
this.onClick = this.onClick.bind(this);
this.onChange = this.onChange.bind(this);
}
onClick(event) {
event.preventDefault();
const { memo, removeMemo } = this.props;
removeMemo(memo._id);
}
onChange(event) {
const { memo, updateMemoContent } = this.props;
const content = event.target.value;
this.setState({
textAreaValue: content
});
updateMemoContent(memo._id, content);
}
componentWillReceiveProps(nextProps) {
if (this.state.textAreaValue !== nextProps.memo.content) {
this.setState({
textAreaValue: nextProps.memo.content
});
}
}
render() {
const { memo } = this.props;
const { textAreaValue } = this.state;
return (
<div className="memo-item">
<a href="#" onClick={this.onClick} className="remove-button">
×
</a>
<textarea
className="textarea"
value={textAreaValue}
onChange={this.onChange}
/>
</div>
);
}
}
MemoItem.propTypes = {
memo: React.PropTypes.object.isRequired,
removeMemo: React.PropTypes.func.isRequired,
updateMemoContent: React.PropTypes.func.isRequired,
};
ポイント
- ReactのStateを使ってテキストエリアの値を表示している
- テキストエリアへの文字入力を検知したら
setState()
で更新- Reactの機能により自動的に画面が書き換わる
- MemoItemの
componentWillReceiveProps()
で他のブラウザからの変更も検知して、テキストエリア内の文字を更新している
コードを書き換えたら、Webブラウザで動作確認します。
メモを編集してWebブラウザをリロードしてみてください。
今度はメモの変更内容が保持されるようになりました。
また、他のWebブラウザでにリアルタイムに同期されるようになりました。
次のステップに進みましょう。