Reputation: 101
I found a great tutorial on using React with Firebase for a very simple use of just storing a text field's data in a database, but I'm stumped on how to convert it to using Hooks. There aren't many tutorials I could find out there on using Hooks + Firebase, so I'd appreciate any help!
import React, {useState} from 'react'
import fire from './fire'
import './App.css'
const App = () => {
let [messageList, setMessageList] = useState([])
const handleSubmit = (e) => {
e.preventDefault()
}
return(
<section>
<form onSubmit={handleSubmit}>
<input type="text"></input>
<button>Test</button>
</form>
<span>Messages: {messageList}</span>
</section>
)
}
class ThisWorksButNotWithHooks extends React.Component {
constructor(props) {
super(props);
this.state = { messages: [] }; // <- set up react state
}
componentWillMount(){
/* Create reference to messages in Firebase Database */
let messagesRef = fire.database().ref('messages').orderByKey().limitToLast(100);
messagesRef.on('child_added', snapshot => {
/* Update React state when message is added at Firebase Database */
let message = { text: snapshot.val(), id: snapshot.key };
this.setState({ messages: [message].concat(this.state.messages) });
})
}
addMessage(e){
e.preventDefault(); // <- prevent form submit from reloading the page
/* Send the message to Firebase */
fire.database().ref('messages').push( this.inputEl.value );
this.inputEl.value = ''; // <- clear the input
}
render() {
return (
<form onSubmit={this.addMessage.bind(this)}>
<input type="text" ref={ el => this.inputEl = el }/>
<input type="submit"/>
<ul>
{ /* Render the list of messages */
this.state.messages.map( message => <li key={message.id}>{message.text}</li> )
}
</ul>
</form>
);
}
}
export default App;
I know it's communicating with Firebase properly because ThisWorksButNotWithHooks works, thanks to https://www.codementor.io/yurio/all-you-need-is-react-firebase-4v7g9p4kf . I learn best by seeing a barebones simple example and working up from there by trial and error, so if I knew how to do this with Hooks I could work up to more complex usage.
Thank you!
Upvotes: 2
Views: 5295
Reputation: 2490
The react-firebase-hooks
library provides convenience methods for Hooks + Firebase. You can take a look at their useList
implementation to get some ideas.
Upvotes: 0
Reputation: 131
According to the Firebase Realtime API page, the useEffect() body should end with
return () => messagesRef.off('value', listener)
because on() returns the listener, not the unlistener. Firestore's onDataSnapshot() is the one that returns the unlistener.
Upvotes: 2
Reputation: 1041
Something like this should work. I haven't really focused on your Firebase logic or returned html, but just showed how you could use the useEffect and useState hooks:
const App = () => {
const [messageList, setMessageList] = useState([])
const [inputEl, setInputEl] = React.useState(null)
React.useEffect(() => {
/* Create reference to messages in Firebase Database */
let messagesRef = fire.database().ref('messages').orderByKey().limitToLast(100);
// As you are using a listener, declare it so it can be returned
const listener = messagesRef.on('child_added', snapshot => {
// Below logic just adds to the current 'messages' state
const message = { text: snapshot.val(), id: snapshot.key };
const updatedMessagesArray = [...messageList].push(message)
setMessageList(updatedMessagesArray)
})
return () => listener() // <== the listener returns the unsubscribe function, which the hook will automatically run when the component unmounts.
}, []) // <== run once onMount
async function addMessage(e){
e.preventDefault(); // <- prevent form submit from reloading the page
/* Send the message to Firebase */
await fire.database().ref('messages').push( inputEl.value );
setInputEl(null)
}
const handleSubmit = (e) => {
e.preventDefault()
}
return(
<section>
<form onSubmit={handleSubmit}>
<input type="text"></input>
<button>Test</button>
</form>
<span>Messages: {messageList}</span>
</section>
)
}
Passing an empty array as the second arg to the useEffect hook will tell it only to run once when the component mounts, and returning the listener will let the hook unsubscribe the listener when the component unmounts.
Upvotes: 4