ReactNative 의 FlatList 사용 및 구덩이 밟 기 패키지 요약

14351 단어 ReactNativeFlatList
RN 에서 FlatList 는 고성능 목록 구성 요소 로 ListView 구성 요소 의 업그레이드 버 전 으로 성능 이 크게 향상 되 었 습 니 다.물론 목록 기능 을 실현 할 때 FlatList 를 사용 하 는 것 을 권장 합 니 다.ListView 를 사용 하지 말고 ScrollView 를 사용 하지 마 십시오.FlatList 라 고 했 으 니 지원 하 는 기능 부터 복습 해 보 세 요.
  • 완전 크로스 플랫폼.
  • 수평 레이아웃 모드 를 지원 합 니 다.
  • 줄 구성 요소 가 표시 되 거나 숨 길 때 리 셋 이 벤트 를 설정 할 수 있 습 니 다.
  • 단독 헤드 구성 요 소 를 지원 합 니 다.
  • 단독 꼬리 구성 요 소 를 지원 합 니 다.
  • 사용자 정의 줄 구분 선 을 지원 합 니 다.
  • 드 롭 다운 리 셋 을 지원 합 니 다.
  • 로 딩 을 지원 합 니 다.
  • 지정 한 줄 로 이동(ScrollToIndex)을 지원 합 니 다.
  • 오늘 의 이 글 은 어떻게 사용 하 는 지 구체 적 으로 소개 하지 않 습 니 다.어떻게 사용 하 는 지 보고 싶 으 면 제 GitHubhttps://github.com/xiehui999/helloReactNative의 예 시 를 참고 하 십시오.오늘 의 이 글 은 내 가 사용 하 는 과정 에서 느 낀 비교적 큰 구 덩이 를 소개 하고 FlatList 에 대한 2 차 포장 을 소개 한다.
    다음은 간단 한 예 를 들 어 보 겠 습 니 다.우리 문장 에 도 이런 예 가 있어 토론 을 시작 했다.
    
        <FlatList
          data={this.state.dataList} extraData={this.state}
          refreshing={this.state.isRefreshing}
          onRefresh={() => this._onRefresh()}
          keyExtractor={(item, index) => item.id}
          ItemSeparatorComponent={() => <View style={{
            height: 1,
            backgroundColor: '#D6D6D6'
          }}/>}
          renderItem={this._renderItem}
          ListEmptyComponent={this.emptyComponent}/>
          
          
      //     
        emptyComponent = () => {
        return <View style={{
          height: '100%',
          alignItems: 'center',
          justifyContent: 'center',
        }}>
          <Text style={{
            fontSize: 16
          }}>        </Text>
        </View>
      }
    위의 코드 에서 저 희 는 주로 ListEmpty Component 를 살 펴 보 겠 습 니 다.데이터 가 없 을 때 채 워 진 레이아웃 을 표시 합 니 다.일반적인 상황 에서 저 희 는 중간 에 알림 정 보 를 표시 하고 편리 함 을 위해 데이터 없 이 새로 고침 을 간단하게 보 여 줍 니 다.위의 코드 는 데이터 가 중간 에 표시 되 지 않 은 것 처럼 보이 지만 실행 한 후에 당신 은 눈 이 멀 었 습 니 다.데이터 가 맨 위 에 중간 에 표시 되 지 않 았 습 니 다.이때 높이 는 100%효과 가 없 었 습 니 다.물론 flex:1 을 사용 하여 View 의 높 은 보 기 를 남 은 전체 화면 에 채 우려 고 시 도 했 지만 효과 가 없 었 습 니 다.
    그런데 왜 효과 가 없 는 지 궁금 하 니까 소스 코드 를 찾 아 보 자.원본 경 로 는 react-native-->Libraries-->Lists 에 있 습 니 다.목록 의 구성 요 소 는 모두 이 디 렉 터 리 아래 에 있 습 니 다.먼저 FlatList 파일 에서 키 워드 를 검색 합 니 다.ListEmpty Component 에서 이 구성 요소 가 사용 되 지 않 았 음 을 발견 하면 render 로 계속 갑 니 다.
    
     render() {
      if (this.props.legacyImplementation) {
       return (
        <MetroListView
         {...this.props}
         items={this.props.data}
         ref={this._captureRef}
        />
       );
      } else {
       return (
        <VirtualizedList
         {...this.props}
         renderItem={this._renderItem}
         getItem={this._getItem}
         getItemCount={this._getItemCount}
         keyExtractor={this._keyExtractor}
         ref={this._captureRef}
         onViewableItemsChanged={
          this.props.onViewableItemsChanged && this._onViewableItemsChanged
         }
        />
       );
      }
     }
    
    MetroListView(내부 실행 은 ScrollView)는 낡은 ListView 실현 방식 이 고 VirtualizedList 는 새로운 성능 이 비교적 좋 은 실현 이다.우 리 는 이 서류 에 간다.
    
      //      
      const itemCount = this.props.getItemCount(data);
      if (itemCount > 0) {
        ....      
      } else if (ListEmptyComponent) {
       const element = React.isValidElement(ListEmptyComponent)
        ? ListEmptyComponent // $FlowFixMe
        : <ListEmptyComponent />;
       cells.push(
        /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
         * comment suppresses an error when upgrading Flow's support for React.
         * To see the error delete this comment and run Flow. */
        <View
         key="$empty"
         onLayout={this._onLayoutEmpty}
         style={inversionStyle}>
         {element}
        </View>,
       );
      }
    여기 서 우리 가 정의 하 는 ListEmpty Component 외 에 view 를 보 았 습 니 다.이 view 는 스타일 inversionStyle 을 추가 하 였 습 니 다.
    
    const inversionStyle = this.props.inverted
       ? this.props.horizontal
        ? styles.horizontallyInverted
        : styles.verticallyInverted
       : null;
       
      :
    verticallyInverted: {
      transform: [{scaleY: -1}],
     },
     horizontallyInverted: {
      transform: [{scaleX: -1}],
     },
    
    위의 스타일 은 애니메이션 을 추가 한 것 입 니 다.높이 를 설정 하지 않 았 기 때문에 ListEmpty Component 에서 height:'100%'나 flex:1 을 사용 해도 효과 가 없고 높이 를 올 리 지 못 했 습 니 다.
    우리 가 원 하 는 효 과 를 실현 하기 위해 서 는 height 를 구체 적 인 값 으로 설정 해 야 합 니 다.그럼 이 값 을 얼마나 설정 해 야 하나 요?FlatList 에 스타일 을 설정 하면 배경 속성 에 색상 을 설정 합 니 다.FlatList 는 기본적으로 남 은 화면 을 차지 하 는 높이(flex:1)입 니 다.그러면 ListEmpty Component 에서 view 의 높이 를 FlatList 의 높이 로 설정 할 수 있 습 니 다.FlatList 의 높이 를 얻 으 려 면 onLayout 를 통 해 얻 을 수 있 습 니 다.
    코드 조정:
    
    //    
    fHeight = 0;
    
        <FlatList
          data={this.state.dataList} extraData={this.state}
          refreshing={this.state.isRefreshing}
          onRefresh={() => this._onRefresh()}
          keyExtractor={(item, index) => item.id}
          ItemSeparatorComponent={() => <View style={{
            height: 1,
            backgroundColor: '#D6D6D6'
          }}/>}
          renderItem={this._renderItem}
          onLayout={e => this.fHeight = e.nativeEvent.layout.height}
          ListEmptyComponent={this.emptyComponent}/>
          
          
      //     
        emptyComponent = () => {
        return <View style={{
          height: this.fHeight,
          alignItems: 'center',
          justifyContent: 'center',
        }}>
          <Text style={{
            fontSize: 16
          }}>    </Text>
        </View>
      }
    
    
    위의 조정 을 통 해 안 드 로 이 드 에서 실 행 될 때 우리 가 원 하 는 효 과 를 거 두 었 음 을 알 수 있 습 니 다.그러나 iOS 에 서 는 제어 할 수 없고 가끔 중간 에 표시 되 며 가끔 은 맨 위 에 표 시 됩 니 다.이 유 는 iOS 에서 onLayout 호출 시기 가 Android 와 약간 다 르 기 때 문 입 니 다.
    그래서 변 경 된 값 을 empty Component 에 사용 하기 위해 fHeight 를 state 에 설정 합 니 다.
    
    state={
      fHeight:0
    }
    
    onLayout={e => this.setState({fHeight: e.nativeEvent.layout.height})}
    
    이렇게 설정 하면 완벽 하 겠 죠?하지만...............................................................................인쇄 로그 의 발견 값 은 0 과 측정 후의 값 을 왔 다 갔다 합 니 다.여기 서 우 리 는 단지 측정 한 값 만 필요 하기 때문에 onLayout 를 수정 합 니 다.
    
               onLayout={e => {
                 let height = e.nativeEvent.layout.height;
                 if (this.state.fHeight < height) {
                   this.setState({fHeight: height})
                 }
               }}
    처 리 를 거 친 후에 ios 에서 우리 가 원 하 는 효 과 를 완벽 하 게 실현 했다.
    위의 구 덩이 를 제외 하고 개인 적 으로 또 하나의 구 덩이 는 onEndReached 라 고 생각 합 니 다.만약 에 우리 가 드 롭 다운 로드 기능 을 실현 하면 모두 이 속성 을 사용 합 니 다.이 속성 을 언급 하면 우 리 는 당연히 onEndReached Threshold 를 언급 해 야 합 니 다.FlatList 에서 onEndReached Threshold 는 number 유형 입 니 다.그 는 구체 적 인 밑부분 이 얼마나 멀 었 을 때 onEndReached 를 촉발 하 는 지 표시 합 니 다.주의해 야 할 것 은 FlatList 와 ListView 의 onEndReached Threshold 가 나타 내 는 의 미 는 다 릅 니 다.ListView 에서 onEndReached Threshold 는 구체 적 인 아래쪽 에 픽 셀 이 얼마나 있 는 지 표시 할 때 onEndReached 를 터치 합 니 다.기본 값 은 1000 입 니 다.한편,FlatList 는 하나의 배수(픽 셀 이 아 닌 비율 이 라 고도 함)를 나타 내 고 기본 값 은 2 입 니 다.
    그럼 관례 대로 아래 를 보면 서 이 루어 지 겠 습 니 다.
    
          <FlatList
            data={this.state.dataList}
            extraData={this.state}
            refreshing={this.state.isRefreshing}
            onRefresh={() => this._onRefresh()}
            ItemSeparatorComponent={() => <View style={{
              height: 1,
              backgroundColor: '#D6D6D6'
            }}/>}
            renderItem={this._renderItem}
            ListEmptyComponent={this.emptyComponent}
            onEndReached={() => this._onEndReached()}
            onEndReachedThreshold={0.1}/>
    그리고 저희 가 componentDid Mount 에 다음 코드 를 넣 을 게 요.
    
      componentDidMount() {
        this._onRefresh()
      }
    즉,첫 페이지 의 데 이 터 를 불 러 오기 시작 하고 드 롭 다운 실행 onEndReached 에 들 어가 더 많은 데 이 터 를 불 러 오고 데이터 원본 dataList 를 업데이트 하 는 것 입 니 다.완벽 해 보이 지만...........................................................................................onRefresh 로 데 이 터 를 불 러 오 는 데 시간 이 걸 립 니 다.데이터 가 요청 되 기 전에 render 방법 으로 실 행 됩 니 다.데이터 가 없 기 때문에 onEndReached 방법 으로 한 번 실 행 됩 니 다.이 때 는 두 번 의 데 이 터 를 불 러 온 셈 입 니 다.
    onEndReached 가 몇 번 을 실행 하 는 지 에 대해 서 는 onEndReached Threshold 의 값 을 정 해 야 합 니 다.그래서 우 리 는 반드시 onEndReached Threshold 를 신중하게 설정 해 야 합 니 다.만약 에 픽 셀 설정 으로 이해 하면 비교적 큰 숫자 로 설정 합 니 다.예 를 들 어 100,그러면 망 했 습 니 다.개인 감각 설정 0.1 이 좋 은 값 입 니 다.
    위의 분석 을 통 해 개인 적 으로 FlatList 에 대해 2 차 포장 을 할 필요 가 있다 고 느 꼈 습 니 다.자신의 수요 에 따라 저 는 2 차 포장 을 했 습 니 다.
    
    import React, {
      Component,
    } from 'react'
    import {
      FlatList,
      View,
      StyleSheet,
      ActivityIndicator,
      Text
    } from 'react-native'
    import PropTypes from 'prop-types';
    
    export const FlatListState = {
      IDLE: 0,
      LoadMore: 1,
      Refreshing: 2
    };
    export default class Com extends Component {
      static propTypes = {
        refreshing: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
      };
      state = {
        listHeight: 0,
      }
    
      render() {
        var {ListEmptyComponent,ItemSeparatorComponent} = this.props;
        var refreshing = false;
        var emptyContent = null;
        var separatorComponent = null
        if (ListEmptyComponent) {
          emptyContent = React.isValidElement(ListEmptyComponent) ? ListEmptyComponent : <ListEmptyComponent/>
        } else {
          emptyContent = <Text style={styles.emptyText}>        </Text>;
        }
        if (ItemSeparatorComponent) {
          separatorComponent = React.isValidElement(ItemSeparatorComponent) ? ItemSeparatorComponent :
            <ItemSeparatorComponent/>
        } else {
          separatorComponent = <View style={{height: 1, backgroundColor: '#D6D6D6'}}/>;
        }
        if (typeof this.props.refreshing === "number") {
          if (this.props.refreshing === FlatListState.Refreshing) {
            refreshing = true
          }
        } else if (typeof this.props.refreshing === "boolean") {
          refreshing = this.props.refreshing
        } else if (typeof this.props.refreshing !== "undefined") {
          refreshing = false
        }
        return <FlatList
          {...this.props}
          onLayout={(e) => {
            let height = e.nativeEvent.layout.height;
            if (this.state.listHeight < height) {
              this.setState({listHeight: height})
            }
          }
          }
          ListFooterComponent={this.renderFooter}
          onRefresh={this.onRefresh}
          onEndReached={this.onEndReached}
          refreshing={refreshing}
          onEndReachedThreshold={this.props.onEndReachedThreshold || 0.1}
          ItemSeparatorComponent={()=>separatorComponent}
          keyExtractor={(item, index) => index}
          ListEmptyComponent={() => <View
            style={{
              height: this.state.listHeight,
              width: '100%',
              alignItems: 'center',
              justifyContent: 'center'
            }}>{emptyContent}</View>}
        />
      }
    
      onRefresh = () => {
        console.log("FlatList:onRefresh");
        if ((typeof this.props.refreshing === "boolean" && !this.props.refreshing) ||
          typeof this.props.refreshing === "number" && this.props.refreshing !== FlatListState.LoadMore &&
          this.props.refreshing !== FlatListState.Refreshing
        ) {
          this.props.onRefresh && this.props.onRefresh()
        }
    
      };
      onEndReached = () => {
        console.log("FlatList:onEndReached");
        if (typeof this.props.refreshing === "boolean" || this.props.data.length == 0) {
          return
        }
        if (!this.props.pageSize) {
          console.warn("pageSize must be set");
          return
        }
        if (this.props.data.length % this.props.pageSize !== 0) {
          return
        }
        if (this.props.refreshing === FlatListState.IDLE) {
          this.props.onEndReached && this.props.onEndReached()
        }
      };
    
    
      renderFooter = () => {
        let footer = null;
        if (typeof this.props.refreshing !== "boolean" && this.props.refreshing === FlatListState.LoadMore) {
          footer = (
            <View style={styles.footerStyle}>
              <ActivityIndicator size="small" color="#888888"/>
              <Text style={styles.footerText}>     …</Text>
            </View>
          )
        }
        return footer;
      }
    }
    const styles = StyleSheet.create({
      footerStyle: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
        padding: 10,
        height: 44,
      },
      footerText: {
        fontSize: 14,
        color: '#555555',
        marginLeft: 7
      },
      emptyText: {
        fontSize: 17,
        color: '#666666'
      }
    })
    
    
    proptypes 에서 저 희 는 oneOf Type 을 사용 하여 refreshing 형식 을 제한 합 니 다.ListEmpty Component 가 정의 가 있 으 면 사용자 정의 분 View 를 사용 하 는 것 입 니 다.같은 ItemSeparatorComponent 도 사용자 정의 할 수 있 습 니 다.
    드 롭 다운 으로 데 이 터 를 불 러 올 때 ListFooter Component 를 정의 합 니 다.사용자 가 데 이 터 를 불 러 오고 있 음 을 알려 줍 니 다.refreshing 속성 이 boolean 이 라면 드 롭 다운 로 딩 기능 이 없다 는 뜻 입 니 다.number 형식 이 라면 pageSize 를 전송 해 야 합 니 다.데이터 원본 길이 와 pageSize 의 나머지 가 0 인지,더 많은 데이터 가 있 는 지 판단 합 니 다.물론 위의 코드 도 간단 합 니 다.쉽게 알 아 볼 수 있 을 거 라 고 믿 습 니 다.다른 것 은 많이 소개 하지 않 겠 습 니 다.이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기