# github trends list

- order: 1

从 github 拉取热门趋势，演示网络请求与 ListView 综合使用。

---

```js
/** @jsx createElement */
import { createElement, PureComponent, Component, render } from 'rax';
import View from 'nuke-view';
import Text from 'nuke-text';
import RefreshControl from 'nuke-refresh-control';
import Touchable from 'nuke-touchable';
import ListView from 'nuke-list-view';
import Iconfont from 'nuke-iconfont';
import Navigator from 'nuke-navigator';

class ListItem extends PureComponent {
  render() {
    const { id, repo, url, stars, forks, description } = this.props;
    return (
      <Touchable
        key={id}
        style={styles.cellItem}
        onPress={() => {
          Navigator.push(url);
        }}>
        <Text style={styles.repo}>{repo}</Text>
        <Text style={styles.desc}>{description}</Text>

        <View style={styles.subLine}>
          <Text style={styles.icon}>&#xe658;</Text>
          <Text style={styles.subtext}>{stars}</Text>
          <Text style={styles.icon}>&#xe65b;</Text>
          <Text style={styles.subtext}>{forks}</Text>
        </View>
      </Touchable>
    );
  }
}
class Loading extends PureComponent {
  render() {
    return (
      <View style={styles.fullLoading}>
        <Text style={styles.fullLoadingText}>loading...</Text>
      </View>
    );
  }
}

class ListViewDemo extends Component {
  constructor() {
    super();
    this.state = {
      data: [],
      isRefreshing: false,
      refreshText: '↓ 下拉刷新'
    };
    this.onRefresh = this.onRefresh.bind(this);
    this.renderItem = this.renderItem.bind(this);
    this.onLoadMore = this.onLoadMore.bind(this);
    this.renderHeader = this.renderHeader.bind(this);
    this.renderFooter = this.renderFooter.bind(this);
    this.page = 1;
  }
  componentDidMount() {
    Iconfont({
      name: 'trends',
      url: 'https://at.alicdn.com/t/font_651722_e6h6njwk7f1or.ttf'
    });
    this.fetchData().then((data) => {
      this.page = this.page + 1;
      this.setState({
        data: this.formatData(data.items)
      });
    });
  }
  fetchData() {
    const that = this;
    return fetch(
      'https://api.github.com/search/repositories?q=created:%3C2018-04-30+language:javascript&sort=stars&order=desc&page=' +
        this.page +
        '&per_page=10',
      {
        mode: 'cors',
        dataType: 'json',
        method: 'GET'
      }
    ).then((response) => {
      return response.json();
    });
  }
  formatData(data) {
    data.map((item, index) => {
      item = {
        repo: item.full_name,
        url: item.html_url,
        stars: item.stargazers_count,
        forks: item.forks_count,
        description: item.description,
        id: item.id
      };
      data[index] = item;
    });
    return data;
  }
  onItemPress(index) {
    console.log(`clicked ${index}`);
  }
  onRefresh(e) {
    this.page = 1;
    this.setState({
      isRefreshing: true,
      refreshText: '加载中'
    });
    this.fetchData().then(
      (data) => {
        this.page = this.page + 1;
        this.setState({
          isRefreshing: false,
          data: this.formatData(data.items),
          refreshText: '↓ 下拉刷新'
        });
      },
      (error) => {}
    );
  }

  onLoadMore() {
    this.fetchData().then((data) => {
      this.page = this.page + 1;
      let newdata = this.formatData(data.items);
      this.setState({
        data: this.state.data.concat(newdata)
      });
      this.refs.trendslist.resetLoadmore();
    });
  }
  renderHeader() {
    return (
      <RefreshControl style={styles.refresh} refreshing={this.state.isRefreshing} onRefresh={this.onRefresh}>
        <Text style={styles.loadingText}>{this.state.refreshText}</Text>
      </RefreshControl>
    );
  }
  renderItem(item, index) {
    return <ListItem {...item} />;
  }
  renderFooter() {
    return (
      <View style={[styles.loading]}>
        <Text style={styles.loadingText}>加载中...</Text>
      </View>
    );
  }
  render() {
    const { data } = this.state;
    // alert('length:' + data.length);
    return data.length ? (
      <ListView
        ref="trendslist"
        renderHeader={this.renderHeader}
        renderFooter={this.renderFooter}
        renderRow={this.renderItem}
        dataSource={data}
        style={styles.listContainer}
        onEndReached={this.onLoadMore}
      />
    ) : (
      <Loading />
    );
  }
}
const styles = {
  listContainer: {
    flex: 1
  },
  cellItem: {
    backgroundColor: '#ffffff',
    'backgroundColor:active': '#f2f3f7',
    minHeight: 160,
    width: 750,
    padding: 30,
    borderBottomWidth: 1,
    borderBottomStyle: 'solid',
    borderBottomColor: '#e6e7eb'
  },
  repo: {
    fontSize: 40,
    color: '#0366d6',
    marginBottom: 30
  },
  desc: {
    fontSize: 28,
    color: '#999999',
    marginBottom: 20
  },
  icon: {
    fontSize: 32,
    marginRight: 10,
    lineHeight: 50,
    color: '#5F646E',
    fontFamily: 'trends'
  },
  subLine: {
    flexDirection: 'row'
  },
  subtext: {
    color: '#5F646E',
    fontSize: 28,
    lineHeight: 50,
    marginRight: 40
  },
  refresh: {
    height: 80,
    width: 750,
    backgroundColor: '#cccccc',
    justifyContent: 'center',
    alignItems: 'center'
  },

  loading: {
    height: 80,
    width: 750,
    flexDirection: 'row',
    backgroundColor: '#cccccc',
    alignItems: 'center',
    justifyContent: 'center'
  },
  loadingText: {
    color: '#666666'
  },
  fullLoading: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center'
  },
  fullLoadingText: {
    fontSize: 28,
    color: '#999999'
  }
};

render(<ListViewDemo />);
```
