はじめに
React
とFirebase
を使用したチャットシステムを作成していました。
それまではFirebase
はログイン状態を管理するために使用していましたが、RealtimeDatabase
の操作を学びたかったため、メッセージの追加、削除も管理するようにしました。
その時に学んだことを記録します。
この記事のコードでできること
削除ボタンを押した際、`更新してください`というポップアップが表示されます。現在の状態
- URL: Reactチャット
- Github: kaibara/React-chat
実装
ファイル構造
今回のファイル構造はこのようになっています。
src ー App.js
|ー components
| |ー ChatMEssage.js
| |ー ChatForm.js
|
|ー firebase
|ー firebase.js
FirebaseRealtimeDatabase
まずはFirebase
のRealtimeDatabase
に接続します。
アプリの名前の設定などができていない場合は、ReactにFirebaseでGoogleアカウントの情報を反映させるを参考にしてください。
Firebase console
Firebase console
でアプリの名前が設定できたら、開発 -> Database
を選択してください。
最初にCloud Firestore
が表示されますが、それではなく、その下にあるRealtime Database
を選びましょう。
次に、データベースを作成
を選択し、テストモード
を選んでください。
firebase init
ここまでできたら端末の操作に移ります。
$ firebase init
// Database,Hostingを選択
// 基本的に全部Enterで可能、カスタマイズしたい場合は各自で変更
上のコマンドの処理が終わったら、作成されたdatabase.rules.json
を確認してください。
{
"rules": {
".read": "true",
".write": "true"
}
}
このようになっていますか?
なっていなかったら、上のように変更してください
コードから接続
最後に、ファイル、コードからFirebaseRealtimeDatabae
に接続できるようにします。
行うことはfirebase
の設定が記載されたファイルにDatabase
に関連するコードを追加するだけです。
config
で定義しているコードはReactにFirebaseを使ったログイン機能を実装する
を参考に持ってきてください。
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/database'
//追加するコード1つ目
const config = {
apiKey: "***",
authDomain: "***",
databaseURL: "***",
projectId: "***",
storageBucket: "***",
messagingSenderId: "***"
}
export const firebaseApp = firebase.initializeApp(config)
export const firebaseDB = firebase.database()
//追加するコード2つ目
このようなファイルを作成することでfirebase
とRealtimeDatabase
を使用できるようになります。
データの追加
続いて、データ、メッセージをRealtimeDatabase
に追加できるようにします。
では、解説していきます。
ChatForm.js
ここではユーザー名及びメッセージを入力するフォームを作成しています。
RealtimeDatabae
と直接の関わりはありません。
ここで入力された値がRealtimeDatabase
に渡されるため、src/App.js
で定義されたイベントと照らし合わせて確認してください。
import React,{Component} from 'react'
import firebase from 'firebase/app'
import {firebaseApp} from '../firebase/firebase'
class ChatForm extends Component {
render(){
return(
<div id='Form'>
<input name='user_name' onChange={this.props.onTextChange} placeholder='名前'/>
<textarea name='text' onChange={this.props.onTextChange} placeholder='メッセージ'/>
<button onClick={this.props.onButtonClick}>送信</button>
</div>
)
}
}
export default ChatForm
ChatMessage.js
ここでは今までのメッセージが表示されます。
メッセージのデータはsrc/App.js
からprops
を使用して渡されます。
RealtimeDatabase
のデータはここに表示されるとだけ覚えておいてください。
import React,{Component} from 'react'
class ChatMessage extends Component {
render(){
return(
<div>
<p>{this.props.message.text}</p>
<p>by {this.props.message.user_name}</p>
</div>
)
}
}
export default ChatMessage
App.js
このファイルがRealtimeDatabase
と直接やり取りをします。
まずはコードをご覧ください。
import React, { Component } from 'react'
import firebase from 'firebase/app'
import { firebaseApp,firebaseDB } from './firebase/firebase'
import ChatMessage from './components/ChatMessage'
import ChatForm from './components/ChatForm'
const messagesRef = firebaseDB.ref('messages')
//RealtimeDatabaseの`messages`という要素にメッセージを保存する
class App extends Component {
constructor(props) {
super(props)
this.onTextChange = this.onTextChange.bind(this)
this.onButtonClick = this.onButtonClick.bind(this)
//このファイルで使用するイベントを明確化している
this.state = {
text : "",
user_name: "",
messages : []
}
}
componentWillMount() {
messagesRef.on('child_added', (snapshot) => {
const m = snapshot.val()
let msgs = this.state.messages
msgs.push({
'text' : m.text,
'user_name' : m.user_name,
})
this.setState({ messages : msgs })
})
}
//下で解説
onTextChange(e) {
// ChatForm.jsで入力された値がthis.state.user_nameとthis.state.textに格納される
if(e.target.name == 'user_name') {
this.setState({
"user_name": e.target.value
});
} else if (e.target.name == 'text') {
this.setState({
"text": e.target.value
});
}
}
onButtonClick() {
//ChatForm.jsの送信ボタンが押されたらthis.stateに格納された値をRealtimeDatabaseに送信する
messagesRef.push({
"user_name" : this.state.user_name,
"text" : this.state.text
})
this.setState({"text": ""})
}
render() {
return (
<div>
<div>
<h2>メッセージログ</h2>
{this.state.messages.map((m, i) => {
return <ChatMessage key={i} message={m} />
})}
//それぞれのメッセージ毎にiというキーを割り当てて、RealtimeDatabaseにある全てのメッセージを表示する
</div>
<ChatForm onTextChange={this.onTextChange} onButtonClick={this.onButtonClick} />
//ChatForm.jsにここで定義した2つのイベントを渡す
</div>
)
}
}
export default App;
eventなどReactの基本的な内容がわかっていればそこまで難しくはないでしょう。
注目していただきたいのはcomponentWillMount()
です。
ここで定義している内容によって、RealtimeDatabae
に送ったメッセージが即座に表示されるようになっています。
では、コメントアウトで解説していきます。
componentWillMount() {
//このファイルのコードが読み込まれる前に行う
messagesRef.on('child_added', (snapshot) => {
//RealtimeDatabseにデータが追加されたら以下の操作を行う
const m = snapshot.val()
//追加されたデータをmとして扱う
let msgs = this.state.messages
//データが追加される前のthis.state.messegesをmsgsに入れる
msgs.push({
'text' : m.text,
'user_name' : m.user_name,
})
//msgsに追加されたデータを追加する
this.setState({ messages : msgs })
//最新のデータをこのコンポーネントで扱えるようmsgsをthis.state.messagesとして定義する
})
}
やっていることはRealtimeDatabae
に追加されたメッセージをthis.state.messages
追加しているだけです。
わかりづらかったらconsole.log()
を使って、一つずつのコードでどのようなデータが扱われているのかを確認してみてください。
データの削除
続いて、データを削除するコードを実装していきます。
ここで扱うのは、ChatMessage.js
とApp.js
です
App.js
App.js
で変更するのはcomponentWillMount()
の中の一箇所だけです。
componentWillMount() {
messagesRef.on('child_added', (snapshot) => {
const m = snapshot.val()
let msgs = this.state.messages
console.log({msgs})
msgs.push({
'text' : m.text,
'user_name' : m.user_name,
'key': snapshot.key
})
this.setState({ messages : msgs })
console.log(this.state.messages)
})
}
データを削除する際に必要なのは、削除したいメッセージとthis.state.messages
で保存しているメッセージが一致するようにすることです。
RealtimeDatabase
にデータが追加される際、snapshot
によって一意のキーが割当られます。
そのキーをthis.state.messages
に保存することで、キーを呼び出せばそのデータを削除できるようになるのです。
実際に削除するのはChatMessage.js
で行います。
ChatMessage.js
RealtimeDatabse
でデータの削除はremove()
だけで行なえます。
そのためには削除したいデータを保存している場所、キーを見つけ出すことが必要ですが、snapshot
のキーをthis.state.messages
に格納したことでメッセージ毎にデータを削除できるようにしました。
import React,{Component} from 'react'
import { firebaseDB } from '../firebase/firebase'
const messagesRef = firebaseDB.ref('messages')
class ChatMessage extends Component {
constructor(props) {
super(props)
this.onRemoveClick = this.onRemoveClick.bind(this)
}
onRemoveClick(){
messagesRef.child(this.props.message.key).remove()
//メッセージ毎にキーがあるためそれを取得して削除する
alert('メッセージはページを更新した後に削除されます')
}
render(){
return(
<div>
<p>{this.props.message.text}</p>
<p">by {this.props.message.user_name}</p>
<button onClick={this.onRemoveClick}>削除</button>
//削除ボタンの実装
</div>
)
}
}
export default ChatMessage
まとめ
今回はページからRealtimeDatabase
へデータの追加、削除する方法をご紹介しました。
削除機能に関して、データを削除してもスグに表示が変更されないため、それが今後の課題となっています。
自身で発見すれば更新しますが、もし良い方法が見つかった際は、コメントなどで教えていただけると助かります。
参考資料
React & Firebaseで簡単なChatアプリを作ってみた
ウェブでのデータの読み取りと書き込み - Firebase Documentation
ウェブ上でデータリストを操作する - Firebase Documentation
How to add remove data function of Firebase Realtime Database - stackoverflow
How to read props on event on React - stackoverflow