• No results found

ListView and Our Master View

In document Programming React Native (Page 72-76)

Since most of our Master view isListViewrigging and eventing, let’s take a

look at what it takes to make a list of objects rendered and reactive within a React NativeListView. As always, take a look at theofficial ListView docs39

for a great overview of theListViewcomponent.

Walkthrough 68

Let’s pick apart our Master view.

1 'use strict';

2

3 var React = require('react-native')

4 var {

5 ListView,

6 } = React

7

8 var Cell = require('./cell')

9

10 var Subscribable = require('Subscribable')

11 var R = React.createClass 12 13 var Master = R({ 14 mixins: [Subscribable.Mixin], 15 16 store: function(){

17 return this.props.store

18 },

So this is how it starts, we’re using the “old style” React conventions where we React.createClass to create a new component. The “new style” is the one

encouraged by ES6, where we extendReact.Componentand make a proper ES6 class- we’ll get to that as well. One of the reasons to use the “old style” is to

be able to utilize existing mixins easily; not to say it isn’t possible with ES6 based code, it is just a lot easier and co-exists with code you’ll see around the Web as of the time of the writing.

Next is our store, which we’ll get to later, and the Subscribable mixin, we’ll

get to those later as well.

Moving on towards the list view.

1 getInitialState: function() {

2 var ds = new ListView.DataSource({rowHasChanged:

3 (r1, r2) => {

4 //hack, need immutability on store for this to be detected

5 return true

6 }

7 })

8 var list = this.store().list()

9 return {

10 dataSource: ds.cloneWithRows(list),

11 }

Walkthrough 69

As a proper React component, it is wise to provide a getInitialState, and

that’s a great place to set our ListView state. If you recall our discussion

about list views, you’ll remember that a list view expect some kind of abstract data source; this will be the following:

1 var ds = new ListView.DataSource({rowHasChanged:

2 (r1, r2) => {

3 //hack, need immutability on store for this to be detected

4 return true

5 }

6 })

Your DataSource is what takes a plain collection of items and makes it into

a proper ListView data source. Here we’re initializing it with a change

function which is responsible for helping theListViewto detect changes in it.

However, we must be careful here - if you’re not doing proper immutable object work, don’t expect it to work since you’ll be changing contents of existing objects which theListViewalready holds. So, given two rows,r1and r2 it is supposed to compute if they are equal or not, and mostly that will

mean comparing instance references. Otherwise, it would mean comparing object IDs or contents, and so on - but that is something you won’t get out of, and you’ll be paying a penalty for comparison.

The best possible way to do this the React way is to use immutability and an immutable collection framework such asImmutable.js40. Immutable

collections, also called Persistent Data Structures, compose really well with React, and you can read more abouthere41and if you’re drawn to academic

papers there’s thisseminal work about the subject42.

To conclude, when you use tools like Immutable.js, it is enough to just say

r1 === r2 and React Native will be able to pick up changes very efficiently.

Otherwise, if your application architecture isn’t based on immutability you may see that ListView would not be able to update itself, in which case I

would try to force updates and return true instead of trying to manually

create the concept of immutable collections without proper immutable collections (such as creating a new object manually when one changes) as long as you’re feeling confident that there is no performance problem. For this book, we have immutable collections implementation in a separate branch of the code; however to keep the discussion simple we’ll need to keep away from that as we want to focus on the core techniques.

Moving on with the code listing, we see this:

40https://facebook.github.io/immutable-js/

41https://en.wikipedia.org/wiki/Persistent_data_structure 42http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf

Walkthrough 70 1 didSelectRow:function(row){

2 this.props.navigator.push({

3 id: 'detail',

4 title: row.title,

5 props: { item: row,

6 store: this.store(),

7 navEvents: this.props.navEvents },

8 })

9 console.log("MASTER: selected", row.title)

10 },

11

12 didDeleteRow:function(row){

13 this.store().remove(row)

14 },

15

16 renderRow:function(row){

17 return (

18 <Cell key={row.id}

19 item={row}

20 onDelete={()=>this.didDeleteRow(row)}

21 onPress={()=> this.didSelectRow(row)}

22 /> 23 ) 24 }, 25 26 render: function() { 27 return (

28 <ListView style={{paddingTop: 50, flex:1}}

29 dataSource={this.state.dataSource}

30 renderRow={this.renderRow}

31 />

32 )

33 }

34 })

We’re skipping the store syncing functionality for now, until we cover the store itself. Let’s start from bottom upwards. First, our render function

is simply a declarative ListView render, with no logic or no complex UI

composition at all; and that holds for a Smart View pattern quite well. We’re doing inline styles for demonstration purposes - the purpose of these styles is to push the list view downwards below the navigation bar, and to make sure the container view flexes maximally along the view port (we’ll get to styling later, but for now you can Google “flexbox” to get an idea of the layout model React Native uses).

We’re supplying thedataSourcewe cooked up through the aptly named prop,

Walkthrough 71

need to give it arenderRowprop, which is just a function returning the React

Native view that is supposed to represent our list item, in our case - the

Cell.

Moving on to renderRow, we’re simply returning our Cell component with a

few important props:

• key - this property is required for collection of components. It’s how

React Native knows how to track our views. Typically you will set it as 1:1 mapping of the identity of the object it renders. In our case it is simply row.id

• onDelete- this is our own custom prop. It signals that the user intends

to delete this item

• onPress - this is our own custom prop. It signals that the user wants to

interact with this item

• item - this is how this cell gets the data model it needs to render, our

item.

Note, that the way each interaction method “knows” what item it needs to handle, is that we simply close over it with a lambda function! These interaction functions simply delegate to each and every interested party. In the case of deletion - the store gets notified about it, and in the case of navigation, well, the navigator gets notified about it. We’ll get to both of these a bit later.

This completes our overview of the Master view. But we do have a couple of holes: our Flux store and navigator. Let’s cover these now, and afterwards we can move on to the rest of the views.

In document Programming React Native (Page 72-76)

Related documents