# FlatList

[官方文檔](https://facebook.github.io/react-native/docs/flatlist.html)    [中文](https://reactnative.cn/docs/0.44/flatlist.html)    [React Native Express](http://www.reactnativeexpress.com/flatlist)

以下內容來自官網高性能的列表組件 只渲染顯示於螢幕內的內容，只更新資料有變動的item 支持以下常用功能:

* 完全跨平台
* 水平佈局
* 行組件顯示或隱藏時可配置回調事件
* 列表的頭部組件
* 列表的尾部組件
* 自定義行間分隔線
* 下拉刷新
* 上拉加載
* 跳轉到指定的index（第index個item）
  * 此方法必須設置getItemLayout。getItemLayout中需帶入每個item的高度，目前找到的都是固定item高度，若item的高度是動態的情況下..尚無頭緒..
  * length=>當前item的高度\
    offset=>目前總高度

    ```
    getItemLayout={(data, index) => (
     {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
    )}
    ```

### 例子<br>

#### 最簡單的例子

```
<FlatList
  data={[{key: 'a'}, {key: 'b'}]}
  renderItem={({item}) => <Text>{item.key}</Text>}
/>
```

#### 較複雜的例子&#x20;

演示如何利用PureComponent來進一步優化性能和減少bug產生的可能（這段需要了解shouldComponentUpdate的機制，以及Component和PureComponent的不同）

* 對於MyListItem組件來說，其onPressItem屬性使用箭頭函數而非bind的方式進行綁定，使其不會在每次列表重新render時生成一個新的函數，從而保證了props的不變性（當然前提是id、selected和title也沒變），避免了觸發自身無謂的重新render。換句話說，如果你是用bind來綁定onPressItem，每次都會生成一個新的函數，導致props在===比較時返回false，從而觸發自身的一次不必要的重新render。
* 給FlatList指定extraData={this.state}屬性，是為了保證state.selected變化時，能夠正確觸發FlatList的更新。如果不指定此屬性，則FlatList不會觸發更新，因為它是一個PureComponent，其props在===比較中沒有變化則不會觸發更新。
* keyExtractor屬性指定使用id作為列表每一項的key。

```
class MyListItem extends React.PureComponent {
  _onPress = () => {
    this.props.onPressItem(this.props.id);
  };

  render() {
    return (
      <SomeOtherWidget
        {...this.props}
        onPress={this._onPress}
      />
    )
  }
}

class MyList extends React.PureComponent {
  state = {selected: (new Map(): Map<string, boolean>)};

  _keyExtractor = (item, index) => item.id;

  _onPressItem = (id: string) => {
    // updater functions are preferred for transactional updates
    this.setState((state) => {
      // copy the map rather than modifying state.
      const selected = new Map(state.selected);
      selected.set(id, !selected.get(id)); // toggle
      return {selected};
    });
  };

  _renderItem = ({item}) => (
    <MyListItem
      id={item.id}
      onPressItem={this._onPressItem}
      selected={!!this.state.selected.get(item.id)}
      title={item.title}
    />
  );

  render() {
    return (
      <FlatList
        data={this.props.data}
        extraData={this.state}
        keyExtractor={this._keyExtractor}
        renderItem={this._renderItem}
      />
    );
  }
}
```

給予的data若有變動，請使用...data 此方法給予新的data，通知flatlist資料有變動

### sample code

![](https://bambooooo.gitbooks.io/react-native/content/React%20Native/images/basic/flatlist/flatlist.png)

```
import React, {Component} from 'react'
import {StyleSheet, View, FlatList, Text} from 'react-native'

var data = [
    {"id":1, title:"title-1"},
    {"id":2, title:"title-2"},
    {"id":3, title:"title-3"},
    {"id":4, title:"title-4"},
    {"id":5, title:"title-5"},
    {"id":6, title:"title-6"},
    {"id":7, title:"title-7"}
]
export default class RecordList extends Component {
  render() {
    return(
      <FlatList
        data={data}
        keyExtractor={(item, index) => item.id}
        renderItem={({item, index}) => <Text>{item.title}</Text>}
        ItemSeparatorComponent={() => this.separator()} 
        onEndReachedThreshold = {0.5}
        onEndReached={()=> {/*快到底了，要加載更多資料..等*/} }
        ListFooterComponent={() => this.footerComponent()}
       />
    );
  }

  separator() {
    return <View style={styles.separator} />
  }

  footerComponent() {
    return (
    <View style={styles.footerView}>
        <Text>最後一筆</Text>
    </View>
    )
  }

}

const styles = StyleSheet.create({
  separator: {
    height: 1,
    backgroundColor: 'red',
  },
  footerView: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
```

### 參考

* <https://juejin.im/post/5978647d51882517905f652e>
* <http://blog.csdn.net/qq_34161388/article/details/72897292>
* <https://dev-blog.apollodata.com/loading-data-into-react-natives-flatlist-9646fa9a199b>
* <http://www.jianshu.com/p/3def7687594c>
