tclarkMEOW
tclarkMEOW

Reputation: 141

Integrating Firebase Realtime Database with React Native App

I am for the first time learning about state, and followed a simple tutorial to create a react native app. The tutorial did not cover using firebase, so this is what I've pieced together. It "works", but does not pull the database data on the first render. I know it's because of the delay in time it takes to grab the data vs my app rendering. But I don't know how I should move logic around to fix it. I feel like I should be using the .then somehow? Or am I doing all of this completely wrong...

import {db} from '../../src/config.js';

let initialMessages = [];
db.ref().once('value', (snapshot) =>{
  snapshot.forEach((child)=>{
    child.forEach(function(childChildSnapshot) {
      initialMessages.push({
        id: childChildSnapshot.key,
        title: childChildSnapshot.val().title,
      })
    })
  })
})
.then()
.catch((error) => {console.error('Error:', error)});

function MessagesScreen(props) {
  const [messages, setMessages] = useState(initialMessages);
  return (
    <Screens>
      <View style={styles.wholeThing}>
         <FlatList
          data={messages}
          keyExtractor={(messages) => messages.id.toString()}
          renderItem={({ item }) => (
            <Card
              title={item.title}
              onPress={() => console.log("hi")}
            />
          )}
          ItemSeparatorComponent={ListItemSeparator}
          contentContainerStyle={styles.messagesList}
          refreshing={refreshing}
          onRefresh={}
        />
      </View>
    </Screens>
  );
}

export default MessagesScreen;

Upvotes: 1

Views: 303

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

By the time you pass initialMessages to the state hook (as its initial value), the initialMessages.push(...) hasn't been called yet.

Instead, you need to call setMessages when the data has loaded:

db.ref().once('value', (snapshot) =>{
  snapshot.forEach((child)=>{
    child.forEach(function(childChildSnapshot) {
      initialMessages.push({
        id: childChildSnapshot.key,
        title: childChildSnapshot.val().title,
      })
    })
    setMessages(initialMessages);
  })
})

Calling setMessages will then rerender the (affected) UI, and that will show the messages.

This of course means that you'll need to pull the useState hook out of MessagesScreen, so that it's also visible in the location where you now call setMessages.

Upvotes: 2

Related Questions