This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

React Native: Build a Notes view with the ListView component

9:37 React lesson by

Displaying lists of data efficiently is an important aspect of native applications. React Native provides the ListView component to accomplish this. We will use the ListView component to display our application's notes that we persisted in Firebase.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Displaying lists of data efficiently is an important aspect of native applications. React Native provides the ListView component to accomplish this. We will use the ListView component to display our application's notes that we persisted in Firebase.

Avatar
Negin

Thanks for this great course. I would like to render a list when app starts as the initial view of application. I'm wondering how to achieve this? Can we use the same lifecycle as react?

In reply to egghead.io
Avatar
Raunaq Singh

With newer versions of React Native, we're supposed to import React separately for Component, et cetera. So I'm pretty sure we can use the same lifecycle methods as React.

In reply to Negin

With this Notes component, we're going to use this ListView because what it is is it's...I can just read it. It's a core component designed for efficient display of vertically scrolling lists of changing data. That's exactly what we're going to have. When we're doing those notes, those notes could be changing.

The biggest thing here, looking at this example, is we create this new instance of DataSource. We pass it this object. Then what we do is we invoked a cloneWithRows method on our dataSource instance that we made. We pass it the rows that we want to loop over. We save that as part of our state.

Then you'll notice down here, we have the ListView component. dataSource is the result of calling cloneWithRows, and then, here, we have this renderRow attribute. We give it a callback function that will invoke for every row in our array we pass to cloneWithRows. Here, rowData will be row 1 and row 2. That's getting passed in as a parameter to our function.

Let's jump over to our code now and go to our Components folder and create a new file called "Notes.js." Require React. We're also going to require our API so that we can communicate with our Firebase API. We're going to require our Separator component we built earlier. The last one is we're going to require our Badge that we built earlier as well.

The things we're going to need. We're going to need a View, Text, a ListView, TextInput, in order to get the new note, StyleSheet for styles, and TouchableHighlight so we can submit that new note. I'm just going to throw in our styles down here.

Now, what we'll do is let's go ahead and create our new Notes component, which extends React.Component. Then, because this component is going to manage its own state, we need to have this constructor function. We're going to set this.state to be a few things. Before we do that, we're always going to call super, passing in props.

Then we're going to have this DataSource. What we're going to pass it is rowHasChanged. We have row1, row2, and then fat arrow. row1 does not equal row2. All right. There we go. Now, in our state, we're going to have a dataSource which is set to what we get back from invoking cloneWithRows.

We're going to pass it this.props.notes, which is all the notes that we'll get from Firebase before we come to this route. We'll have an empty note, and then we'll also have an error.

Let's make a render function now. This is going to be wrapped in a View. The style, as always, is going to be our container. Then what we're going to do...Before we go and we do all the mapping over the rows stuff, let's go ahead and just make our text input box that's going to allow us to add new notes.

As of right now, we don't really have any notes. It wouldn't make sense to make the functionality of repeating or looping over the notes before we have any. What I'm going to do is I'm going to make this function, called "footer," that's going to return us the UI for our footer, which will go right here.

Let's now go and, above render, have footer, which is going to return us a View. What's nice about React is that you can do things like this, where you can have a function which returns some UI and then just invoke that function. You can have it be returned down there, which will show your UI.

We're going to have our TextInput. Some properties to it, style. It's going to styles.searchInput. value is going to be set to this.state.note, and then we're going to have an onChange function. Their placeholder is going to be just "New Note."

Let's go ahead and make this onChange function. Let's call it "handleChange." We'll need to bind this. Now, up here, we'll have handleChange. All it's going to do is it's going to take in an event. It's going to keep our note property on our state object up to date. We're going to say, " note is now nativeEvent.text."

Now that that's good, let's go back down to our footer. Let's add in a button. We're going to use TouchableHighlight to be able to capture that touch event. styles is styles.button.

onPress is going to equal this.handleSubmit, which will make...The underlayColor is going to equal 88D4F5. Inside of here, let's have a Text component with a style of buttonText. Have it say, "Submit," and then we'll close out our TouchableHighlight component.

Now, let's go ahead and make this handleSubmit function. I'm going to do it right below handleChange. Remember, what handleSubmit's responsible for is it's going to take the value or it's going to take this note property on our state and throw it up to Firebase.

We're going to get the note. Then what we can do is reset the state so that'll clear out our input field. Then, if you remember, in our API, we made an addNote method that expects to receive the user's username and a note. It's going to return us a promise. We're going to use the fat arrow syntax here.

Now, inside this, we're going to go and get the notes again. That will return us a promise, which we can .then on. Now, we have the updated data. We can setState. Now, our dataSource is going to be cloneWithRows again, but instead, it's going to be the new data.

If any of that errors, let's go ahead and throw a catch in here. We're going to console.log "Request failed" and the error message, and then we're going to setState error. One last ES6 feature here is that before, you would have to do something like error error, but if these repeat, you can just throw in one, which is really convenient.

Now that that's up, now that our footer is working and it should be making requests to Firebase, let's go ahead and now worry about our ListView. In here, we're going to have our ListView component.

The dataSource we're going to give it is this.state.dataSource, which we made up when we did getInitialState. Remember, renderRow is basically the UI for every item in our dataSource. I'm going to do this.renderRow. We'll make this function here, in a bit.

Then we can also give it a header. You can think of this ListView as like a collection of UI. It's a list. Because of that, we can have a header to it, which is really convenient. At the top of our file, we are going to render the Badge component.

Remember, we need to give it the username, this.props.userInfo. Close that, and then close that, I believe. That's the Badge, and then that's the function. renderHeader takes in a function. Whatever you return will be the header of this ListView.

The last thing we need to do is specify renderRow. Let's come here. We'll add renderRow. Remember, the thing that gets returned from here is going to be the UI for every item in our list. We take in some row data.

We're going to return a View. The style's going to be set to styles.rowContainer. As always, if you're curious about those styles, feel free to go check them out up here. I'll post all this to our GitHub when I'm done or to my GitHub when we're done.

I have a View. Inside of that, I'm just going to render the rowData Text and then, of course, throw in the Separator here. We'll get that nice, great divider between every item. Looks like I forgot to do module.exports.

Then let's set up some prop types on our component. We're expecting to receive some userInfo. As always, that's going to be React.PropTypes.object.isRequired. There are some notes, which is going to be React.PropTypes.object.isRequired as well.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?