最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - react-native flatlist images flicker when list state updating - Stack Overflow

programmeradmin1浏览0评论

I have populated a FlatList with data fetched from Google's firebase backend. The implementation is rather standard, here's a stripped down version:

export default class Day extends Component {

state = { data : [], today: false }


componentWillMount = async () => {

    const { today } = this.state;
    const { calendarDb } = this.props

    await calendarDb.onNewAgenda({ 
          day : today
        , then: this.parseOnListed 
    })
}

parseOnListed = blob => {

    const { data } = this.state;
    data.push(blob)
    this.setState({ data: data })
}


renderItem = ({ item }) => 
    <Hour data = {item}/>


render = () => 
    <FlatList  
        data         = {this.state.data}
        renderItem   = {this.renderItem}
        keyExtractor = {item => item.ID}
    />

}

The issue is that every time a new blob is pushed into data, the <Image/> component in <Hour data={item}/> flickers. This makes the list a no-go in terms of user experience. What gives? <Hour/> is standard as well, and more or less look like this:

const Hour = ({ data }) => 
   <View>
       <Image source={{uri:data.uri}}/>
       <Text> {data.name} </Text>
   </View>

The content of <Text> does not flicker, only the image from <Image .../>

I have populated a FlatList with data fetched from Google's firebase backend. The implementation is rather standard, here's a stripped down version:

export default class Day extends Component {

state = { data : [], today: false }


componentWillMount = async () => {

    const { today } = this.state;
    const { calendarDb } = this.props

    await calendarDb.onNewAgenda({ 
          day : today
        , then: this.parseOnListed 
    })
}

parseOnListed = blob => {

    const { data } = this.state;
    data.push(blob)
    this.setState({ data: data })
}


renderItem = ({ item }) => 
    <Hour data = {item}/>


render = () => 
    <FlatList  
        data         = {this.state.data}
        renderItem   = {this.renderItem}
        keyExtractor = {item => item.ID}
    />

}

The issue is that every time a new blob is pushed into data, the <Image/> component in <Hour data={item}/> flickers. This makes the list a no-go in terms of user experience. What gives? <Hour/> is standard as well, and more or less look like this:

const Hour = ({ data }) => 
   <View>
       <Image source={{uri:data.uri}}/>
       <Text> {data.name} </Text>
   </View>

The content of <Text> does not flicker, only the image from <Image .../>

Share Improve this question edited Jul 20, 2019 at 0:46 xiaolingxiao asked Jul 20, 2019 at 0:42 xiaolingxiaoxiaolingxiao 4,8956 gold badges44 silver badges90 bronze badges 4
  • try using a keyExtractor to uniquely identify a row, this might be due to the whole flatlist re rendering on state update and images being downloaded again – Guruparan Giritharan Commented Jul 20, 2019 at 13:48
  • In the actual codebase I have keyExtractor = {item => item.ID + Math.random()} . But it still flickers – xiaolingxiao Commented Jul 20, 2019 at 14:12
  • 3 why use math.random ? this will make react think that its a new object each time so it might be the issue – Guruparan Giritharan Commented Jul 20, 2019 at 14:18
  • @GuruparanGiritharan ok thats it. fixed the problem thanks! – xiaolingxiao Commented Jul 21, 2019 at 13:46
Add a comment  | 

3 Answers 3

Reset to default 12

Check whether keyExtractor is getting unique ID or not. The flat list is re-rendering on state update and images are downloaded again. Because, each row is not uniquely identified as said in comments by @Guruparan Giritharan.

I found another reason that triggers this issue, of the FlatList flikering on React native. In my case, it happened every time I updated/changed the state of any function component. So, for instance, I was keeping the fetch results (data) and the next-page-id (for the next paginated fetch) in two separate function components:

const [data, setData] = useState([]);
const [pageId, setPageId] = useState(null);

Hence, every time would capture the results of my fetch, I would first set the data update and then the page id. It was the page id update what was causing the flicker.

const onEndReachedFetch = async () ={
    fetch(pageId).then(result => {
        setData(result.Data);
        setPageId(result.pageId);
    });
}

The fix was just to put the state data together so there is a single update instead. Then react is happy and doesn't flicker when adding new items to the list.

const onEndReachedFetch = async () ={
    fetch(pageId).then(result => {
        setResult(result);
    });
}

Beware of any side states that you may be updating in the background, as they may also cause the flickering if they are triggered by anything on the FlatList.

  1. Check whether keyExtractor is getting unique ID.
  2. Use useCallback
<FlatList
    data={data}
    keyExtractor={(item) => item.id}
    renderItem={({ item, index }) => (
        <ListItem
        data={item}
        index={index}
        key={index + 1}
        />
    )}
/>
    
const ListItem = useCallback(({ data, index, }) => {
   return ( 
     <View key={item.id}>
     ...
     </View>
   );
}, []);

发布评论

评论列表(0)

  1. 暂无评论