按键对React Native SectionList进行排序和分组

时间:2019-01-05 20:25:19

标签: javascript arrays sorting react-native expo

我有一个SectionList,其中填充了Firebase中的数据。该列表显示按日期划分的事件信息,当前月份显示为THIS MONTH,其他日期使用其简写值JANFEB等。

我得到的数据很好,并且可以很好地显示,但是我不知道如何按日期对数据数组进行分组。仅供参考,日期以日期字符串'2019-01-05'的形式保存在数据库中,我使用一下矩通过以下方法对其进行格式化:

 formatDateToMonth(date) {
  let fullDate = moment(date);
  fullDate.month();
  const month = fullDate.format('MMM');
  return month.toUpperCase();
}

哪个返回JAN。我运行一个简单的if语句来检查当前月份的title值,并用时刻对其进行格式化,如果匹配,则将title的显示名称更改为THIS MONTH

数据像这样被推送到数组:

listData.push({
  data: [
    {
      id: event,
      eventName: eventObj.eventName,
      location: eventObj.location,
      description: eventObj.description,
      creatorsName: eventObj.creatorsName,
      date: eventObj.date,
      discipline: eventObj.discipline
    }
  ],
  title
});

标题是月份名称,我需要对它进行排序和分组。

这是当前的外观:

enter image description here

这是我希望的样子:(使用伪数据正确显示它) enter image description here

我希望同一月份的每个活动都在同一部分下。

任何帮助都将是惊人的!

完整组件:

import React from 'react';
import {View, StyleSheet, SectionList, TouchableOpacity} from 'react-native';
import { Container, Content , Text, Icon, Spinner } from 'native-base';
import Collapsible from 'react-native-collapsible';
import {f, auth, database} from '../../config/config';
import _ from 'lodash';

import CustomIcon from '../utilities/CustomIcon';

import Month from './Month';
import moment from 'moment';
import Day from './Day';

let today = moment();
let now = today.format("YYYY-MM-DD");
let getCurrentMonth = today.month('MMM');

const monthOrder = [
  'JAN',
  'FEB',
  'MAR',
  'APR',
  'MAY',
  'JUN',
  'JUL',
  'AUG',
  'SEPT',
  'OCT',
  'NOV',
  'DEC'
];

class SectionListItem extends React.Component {

  state = {
    descriptionCollapsed: true
  };

  toggleDescription = () => {
    this.setState({ descriptionCollapsed: !this.state.descriptionCollapsed
    });
  };

  render() {
    let fullDay = moment(this.props.item.date);
    fullDay.day();
    const day = fullDay.format('DD')
    return (
      <View style={styles.sectionListItemContainer}>
      <View style={styles.eventInfoContainer}>
      <View>
      <Day day={day}/>
    </View>
    <TouchableOpacity onPress={this.toggleDescription}>
      <View style={styles.info}>
      <Text style={styles.eventName}>{this.props.item.eventName.toUpperCase()}</Text>
      <Text style={styles.creatorsName}>Coached by {this.props.item.creatorsName}</Text>
    <Text style={styles.location}>{this.props.item.location}</Text>
      </View>
      </TouchableOpacity>
      </View>
      <Collapsible collapsed={this.state.descriptionCollapsed}>
      <EventDescription description={this.props.item.description} discipline={this.props.item.discipline}/>
    </Collapsible>
    </View>
  );
  }
}

class EventDescription extends React.Component {

  render() {
    return (
      <View style={styles.descriptionDropdown}>
      <View >
      <Icon name='arrow-up' type="SimpleLineIcons" style={styles.upArrow} />
    </View>
    <View style={styles.descriptionContainer}>
      <Text style={styles.description}>{this.props.description}</Text>
      </View>
      <View style={styles.iconContainer}>
      {!!this.props.discipline ? (this.props.discipline.map((item, index) => {
      return <View key={index} style={styles.iconMargin}><CustomIcon name={item} size={20} style={styles.iconStyle}/></View>
    })) : null}
  </View>
    </View>
  );
  }
}

class SectionHeader extends React.Component {
  render() {
    return (
      <View style={styles.monthHeader}>
      <Month month={this.props.section.title}/>
    </View>
  );
  }
}

export default class EventList extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      filterCollapsed: true,
      listData: [],
      loading: true,
      refreshing: false
    }
  }

  componentDidMount() {
    this.loadEvents();
  }

  onRefresh = () => {
    this.setState({refreshing: true})
    this.loadEvents();
  }

  formatDateToMonth(date) {
    let fullDate = moment(date);
    fullDate.month();
    const month = fullDate.format('MMM');
    return month.toUpperCase();
  }

  getDateMatches = (date) => {
    return database
      .ref('events')
      .orderByChild('date')
      .startAt(date)
      .once("value")
      .then((snapshot) => {
        let matches = [];
        snapshot.forEach((child) => {
          let val = child.val();
          const valMonth = this.formatDateToMonth(val.date);
          const dateMonth = this.formatDateToMonth(date);
          if (dateMonth === valMonth) {
            matches.push(val);
          }
        });
        return matches;
      });
  }

  loadEvents = () => {
    this.setState({listData: []});
    const that = this;

    database.ref('events').once('value').then((snapshot) => {
      const exists = (snapshot.val() !== null);
      if (exists) {
        data = snapshot.val();
      }
      const listData = that.state.listData;

      let monthData = {title: '', data: []};

      const thisMonth = { title: 'THIS MONTH', data: []};
      const otherMonth = { title: '', data: []};

      for(var event in data) {
        const eventObj = data[event];

        const month = this.formatDateToMonth(eventObj.date);
        let title;

        getCurrentMonth.month();
        const currentMonth = getCurrentMonth.format('MMM');


        if (month === currentMonth.toUpperCase()) {
          title = 'THIS MONTH';
        } else {
          title = month;
        }

        listData.push(
          {
            data: [
              {
                id: event,
                eventName: eventObj.eventName,
                location: eventObj.location,
                description: eventObj.description,
                creatorsName: eventObj.creatorsName,
                date: eventObj.date,
                discipline: eventObj.discipline,
              }
            ],
            title
          }
        );

        // listData.sort((a, b) => {
        //     return (a.title - b.title) || (monthOrder.indexOf(a.title) - monthOrder.indexOf(b.title))
        // });



        that.setState({loading: false, refreshing: false});

      }

    }).catch(error => console.log('error: ', error));
  }


  toggleFilter = () => {
    this.setState({ filterCollapsed: !this.state.filterCollapsed });
  };

  render() {

    if (!!this.state.loading) {
      return (
        <View style={styles.spinner}>
        <Spinner color="#81e6fc"/>
        </View>
    )
    }

    return (
      <Container style={styles.container}>
      <TouchableOpacity style={styles.filterTextContainer} onPress={this.toggleFilter}>
      <Text style={styles.filterText}>FILTER</Text>
      </TouchableOpacity>
      <Collapsible collapsed={this.state.filterCollapsed}>
      <CustomIcon name="Rate" size={50} style={styles.iconStyle}/>
    </Collapsible>
    <Content contentContainerStyle={styles.list}
    onRefresh={this.onRefresh}
    refreshing={this.state.refreshing}
      >
      <SectionList
    renderItem={({item, index}) => {
      return <SectionListItem item={item} index={index}/>
    }}
    renderSectionHeader={({section}) => {
      return <SectionHeader section={section}/>
    }}
    sections={dummyData}
    keyExtractor={(item, index) => item + index}
  >
  </SectionList>
    </Content>
    </Container>
  );
  }
}

1 个答案:

答案 0 :(得分:2)

我认为您不关心分组的年份,因为在这种情况下,2018-01和2019-01都是JAN。但是无论如何,请看下面的示例,我试图注释代码中的每个步骤:

// define your flat list of events
const events = [
	{name: 'dummy one', date: '2019-01-05'},
	{name: 'dummy some', date: '2019-02-04'},
	{name: 'dummy another', date: '2019-01-07'},
	{name: 'dummy really dummy', date: '2019-04-05'},
	{name: 'dummy and funny', date: '2019-06-05'},
	{name: 'dummy not funny', date: '2019-06-22'}
].sort((a, b) => a.date < b.date ? -1 : 1)
// remember to sort them early so you will not have to worry about it anytime later on

// extract distinct names from available events, we are using Set constructor to make sure any key won't be doubled and also that there won't be any empty month
const groupNames = Array.from(new Set(events.map(k => k.date.split('-')[1]))) // split date by hyphen and return only month part

// define place for groups
let groups = {}

// create groups containers from names
groupNames.forEach(k => {
	groups[k] = []
})

// iterate by events and attach every to given group based on its month
events.forEach(k => {
	const month = k.date.split('-')[1]
  groups[month].push(k)
})

// container for demo purposes
let resultHTML = ''

// iterate by groups, if you are unsure about 'for in' loop, use groupNames for that part, and then iterate by events in every group
for(let key in groups) {
	resultHTML += `<h2>${key}</h2>`
  for (let event of groups[key]) {
  	resultHTML += `<p>${event.date} &mdash; ${event.name}</p>`
  }
}

// display results for demo purposes
document.querySelector('.result').innerHTML = resultHTML
<div class="result"></div>