Add a Complete Toggle with React Native Switch

Share this video with your friends

Send Tweet

We'll add a cross platform Switch component to toggle the completeness of each todo item. We'll show how to pass down functions from the parent application to the child row of a ListView.

Mike
Mike
~ 8 years ago

Where you have the

<Row
                  key={key}
                  onComplete={(complete) => this.handleToggleComplete(key, complete)}
                  {...value}
/>

where does complete come from in your arrow function? How is it being passed back up? And for inside Row, even though complete is a prop why don't you call it like <Row complete={ }>?

Jason Brown
Jason Brown(instructor)
~ 8 years ago

It's being passed back up from Row.

How it works is we are passing a prop down to start <Row complete={false} />. This is then passed to the <Switch value={this.props.complete} /> component. Which Switch is a native UI component.

We then additionally pass the onComplete function that is passed to the Switch like <Switch onValueChange={this.props.onComplete} />

When the user toggles the Native component, the onValueChange function gets called which in turn calls our this.props.onComplete function with either true or false. So the Native (iOS/Android) world is actually toggling the value we give it from false => true and or true => false.

We can't call it like <Row complete={ }> because complete is just a boolean value. We need to pass down a way to get notified when the user presses the switch.

Alternatively we could have passed down an onToggle function and not received input from below. Something like

<Row
  onToggle={() => this.handleToggleComplete(key, !value.complete)}
  {...value}
/>

However in these cases I prefer to let the Native component provide me information directly.

The spread operator (the ...) may be confusing but what that's doing is taking everything from the value object and turning it into props. So equivalent would be

<Row
  key={key}
  onComplete={(complete) => this.handleToggleComplete(key, complete)}
 complete={value.complete}
 title={value.title}
 editing={value.editing}
 />

Hopefully this answers all of your questions. If you have more let me know.

Mike
Mike
~ 8 years ago

Would I consider editing to be a synthetic event? Also, (this is for your ToggleEdit lecture later) I tried calling .type on editing and it printed out undefined in the console, why is that? Here's what I had:

onToggleEdit={(editing) => {
                  console.log(editing.type);
                  this.handleToggleEditing(key, editing);
                }}
Jason Brown
Jason Brown(instructor)
~ 8 years ago

The editing that is being passed back us is just a boolean. Meaning true or false.

If you want log the value just log console.log(editing)

Jason Brown
Jason Brown(instructor)
~ 8 years ago

If you are stuck, feel free to put your current code up on a public repository and I'm happy to review it.

Mike
Mike
~ 8 years ago

Here's my code:

https://gist.github.com/huyanhh/930a6c8a02874ded1adc9669cce65b72

I'm trying to extend upon what this lecture series and build a nested ListView. What it's supposed to look like is a custom ListView of "pages" with each page containing a ListView. I'm a little unsure on where I should be passing the props and where I should be managing state since I have to manipulate the dataSource of nested lists. For now, I'm trying to pass up a Page object back to the outer ListView and then set the state up there. Unfortunately the page isn't rendering because I don't have my data sources set up correctly. Should I try managing my state only in app.js? Or should it be delegated to each page within my outer list? I also don't know how to use the key of each Row in regards to updating the outer list if I'm not supposed to hold state in my Page component.

Thanks

Jason Brown
Jason Brown(instructor)
~ 8 years ago

You may not want to complicate things with a double ListView as this would require double data source syncing. You may want to consider a ScrollView of ListViews. However it depends on how much data you're displaying.

This all sounds very complicated in terms of data management. In cases like these it can be easier to externalize data (in something like redux) and then you use componentWillReceiveProps to update the DataSource with your new data.

You can hold your state in your upper Page component.

Do you have an example of your data structure? That may be easier for me to help you.

Mike
Mike
~ 8 years ago

I want to display something that looks like the diary entries of MyFitnessPal. Each day there would be another item appended, and I want to display that list item as a page with its own list. I was thinking it would be too much data to have everything contained in a scroll view. The data structure looks like

{
  day1:
  {
    pageID,
    foodEntry[],
    total,
  }
  day2:
  {
    pageID,
    foodEntry[],
    total,
  }
  ...
}

where each object should be displayed in a separate screen.

Jason Brown
Jason Brown(instructor)
~ 8 years ago

Hey sorry for the late reply. What I would actually recommend is upgrading to React Native .43.

React Native .43 comes with a new FlatList which gets rid of DataSource junk. You can read more about it here http://facebook.github.io/react-native/blog/2017/03/13/better-list-views.html

Mike
Mike
~ 8 years ago

That sounds great! Would you still recommend nesting two FlatLists within each other then using redux to externally manage the data? I came across this issue in the repo today (it's an issue concerning list views and scroll views, and I believe that performance won't be too much of an issue with the new API because most of the content will be offscreen anyway but I wanted to get your opinion on it): https://github.com/facebook/react-native/issues/13038

Jason Brown
Jason Brown(instructor)
~ 8 years ago

Nesting listviews can be tricky but with the new FlatList and SectionList I think everything should be great.

With the new FlatList it's recommended you hold either the data up top and pass it down, or in redux. The reason is if you keep it inside the FlatList items that get rendered, the row items will be unmounted.

So externally in redux is fine OR somewhere above all your lists and just pass it into a FlatList then pass the other data into another FlatList. Just don't hold any state inside the Row Items

Jason Brown
Jason Brown(instructor)
~ 8 years ago

I will also try and find some time to do a quick screencast showing off the FlatLists and SectionLists, and will try and nest them to see how they play together.