0

我发现了很多关于同一个问题的问题,但似乎都没有解决问题。目前我正在使用 redux 来获取对象数组,操作该数据以匹配 SectionList 数据请求,并将其提供给 SectionList 部分道具。在 RenderItem 中,我使用 FlatList 并提供项目道具 section.data。最后,FLatList 中的 renderItem 是一个 PureComponent。我尝试过使用 shouldComponentUpdate,以及其他人建议的 sectionlist 的许多其他道具,但似乎没有任何效果。SectionList 一致地呈现项目 3 次或更多次。这是我的代码:

// SECTION LIST COMPONENT 
import React, { Component } from 'react';
import {
View,
SectionList,
ActivityIndicator,
Text,
AsyncStorage,
} from 'react-native';
import { connect } from 'react-redux';
import { getReleases } from '#modules/Collection/actions';
import { Header, SectionFlatList } from '#common/';
class UserCollections extends Component {
static navigationOptions = {
 header: null,
};
state = {
 records: [],
 refreshing: false,
 userData: {},
 page: 1,
};

componentDidMount() {
 this.getUserCollection();
}

getUserCollection = async () => {
 const token = await AsyncStorage.getItem('access_token');
 const tokenSecret = await AsyncStorage.getItem('access_token');
 const user = await AsyncStorage.getItem('userMeta');
 const userMeta = JSON.parse(user);
 const { username } = userMeta;
 const { page } = this.state;
 const folder = 0;
 const accessData = {
   token,
   tokenSecret,
 };
 try {
   await this.props.dispatch(
     getReleases(accessData, username, folder, page)
   );
 } catch (error) {
   console.log('ERROR', error);
 }
};

handleRefresh = () => {
 this.setState(
   {
     page: 1,
     seed: this.state.seed + 1,
     refreshing: true,
   },
   () => {
     this.getUserCollection();
     this.setState({ refeshing: false });
   }
 );
};
handleLoadMore = () => {
 this.setState(
   {
     page: this.state.page + 1,
   },
   () => {
     this.getUserCollection();
   }
 );
};
renderFooter = () => {
 if (!this.state.loading) return null;
 return (
   <View
     style={{
       paddingVertical: 20,
       borderTopWidth: 1,
       borderColor: '#CED0CE',
     }}
   >
     <ActivityIndicator animating size="large" />
   </View>
 );
};

_sectionKeyExtractor = (section, index) => 'S' + index.toString();

_renderSections = ({ section }) => (
 <SectionFlatList {...this.props} section={section} />
);

render() {
 const { releases } = this.props;

 return (
   <View style={styles.mainContainer}>
     <View style={styles.headerContainer}>
       <Header headerText={'Collection'} />
     </View>
     <View style={styles.contentContainer}>
       <SectionList
         sections={releases}
         extraData={releases}
         renderItem={this._renderSections}
         renderSectionHeader={({ section: { title } }) => (
           <Text style={{ fontWeight: 'bold', color: '#fff' }}>{title}</Text>
         )}
         keyExtractor={this._sectionKeyExtractor}
         refreshing={this.state.refreshing}
         onRefresh={this.handleRefresh}
         onEndReached={this.handleLoadMore}
       />
     </View>
   </View>
 );
}
}

const styles = {
textContainer: {
 paddingBottom: 50,
},
contentContainer: {
 flex: 1,
 backgroundColor: '#000',
 alignItems: 'center',
 justifyContent: 'space-around',
},
contentContainerStyle: {
 flexDirection: 'column',
},
mainContainer: {
 flex: 1,
},
};

mapStateToProps = state => {
console.log('MAP STATE TO PROPAS STATE', state);
return {
 releases: state.UserCollection.releases,
};
};

export default connect(mapStateToProps)(UserCollections);
// SECTIONLIST RENDERITEM COMPONENT (FLATLIST)
import React, { PureComponent } from 'react';
import { FlatList, View } from 'react-native';
import { isEqual } from 'lodash';
import { RecordItem } from './';

class SectionFlatList extends PureComponent {
  listKey = (item, index) => 'D' + index.toString();

  render() {
    const {
      section,
      navigation,
      screenProps: {
        user: {
          accessData: { userMeta },
        },
      },
    } = this.props;
    return (
      <View style={{ flex: 1 }}>
        <FlatList
          data={section.data}
          renderItem={({ item }) => (
            <RecordItem
              item={item}
              navigation={navigation}
              userMeta={userMeta}
            />
          )}
          keyExtractor={this.listKey}
          ListFooterComponent={this.renderFooter}
          contentContainerStyle={styles.contentContainerStyle}
          numColumns={3}
          maxToRenderPerBatch={11}
          initialNumToRender={11}
          removeClippedSubviews={false}
        />
      </View>
    );
  }
}

const styles = {
  contentContainerStyle: {
    flexDirection: 'column',
  },
};

export { SectionFlatList };
import React, { PureComponent } from 'react';
import { TouchableOpacity, View, Image } from 'react-native';
class RecordItem extends PureComponent {
  // shouldComponentUpdate(nextProps, nextState) {
  //   if (this.props.item.instance_id === nextProps.item.instance_id)
  //     return false;
  // }
  render() {
    const { item } = this.props;
    return (
      <View>
        <TouchableOpacity
          key={item.instance_id}
          onPress={() => {
            navigation.navigate('AlbumDetail', {
              item: item,
              inCollection: true,
              inWantlist: false,
              userData: userMeta,
            });
          }}
        >
          <Image
            style={styles.albumCovers}
            source={{ uri: item.basic_information.cover_image }}
          />
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = {
  albumCovers: {
    height: 124,
    width: 124,
    marginLeft: 0.5,
    marginRight: 0.5,
    marginTop: 0.5,
    marginBottom: 0.5,
  },
};

export { RecordItem };

多次渲染的行

4

1 回答 1

0

我有一个类似的问题。我没有使用 redux,所以我的代码不会和你需要的完全一样。我认为你有两个不同的事情都可能导致这种情况。

  1. this.setState 并不总是立即更改状态,因此在 handleLoadMore 中,您可能需要在调用 getUserCollection 之前进行某种检查以确保状态已完成更新,否则它可能会为同一页面调用两次。
  2. FlatList(可能还有 react-native 中的其他类型的列表)有时会重复调用 onEndReached。这可以通过在列表中使用bounces={false} 来减少。即使您这样做了,您仍可能需要创建一个检查,以确保它不会在上次完成更新之前再次尝试更新。也许您可以根据您的目的修改我用来解决问题的方法。这是一个例子:

调用 onEndReached 时调用类似的东西

_onEndList = () => {

if(this.state.showFooter === false && this.state.stuff.length > 0){
    //console.log('getting end list');
    this.AddMoreStuff();


  }else{
//console.log('waiting end list');
    this.waitingForMoreData();
  }

}

然后等待 waitingForMoreData 看起来像这样

 waitingForMoreData(){

   setTimeout(() => {
     if(this.state.showFooter === false && this.state.stuff.length > 0){
       //console.log('getting after waiting end list');

       this.AddMoreStuff();
     }else{
       //console.log('waiting again end list');
       this.waitingForMoreData();
     }
   }, 15000)

 }

AddMoreStuff 在执行其他任何操作之前将 showFooter 设置为 true,并在它需要执行的所有其他操作之后将 showFooter 设置为 false。这些函数正在检查以确保 stuff.length>0 以便在您第一次访问页面时不会在初始填写列表的同时调用它。我正在使用不同的功能来做到这一点。我使用 setTimeout 而不是告诉它不要调用 AddMoreStuff,因为如果您上次调用列表时没有更新列表,有时 FlatList 会停止调用 onEndReached。我希望这会有所帮助,即使我没有使用 redux。

于 2019-06-11T20:02:00.097 回答