V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
letterLim
V2EX  ›  React

请教一个 react native FlatList 的问题

  •  
  •   letterLim · 2 天前 · 471 次点击
    正在做一个聊天应用。 因为要有双向滚动加载的需求放弃了 FlashList 转而使用 FlatList 。 发现发消息新增 item 时。每次渲染都需要 0.8 秒左右。在这期间所有的 setState 都会卡住。 也试了文档中的优化方案感觉效果不大。 有没有大哥知道怎么解决
    4 条回复    2025-02-19 10:07:44 +08:00
    donotquestion
        1
    donotquestion  
       1 天前
    放弃吧,我研究了两周放弃了,傻逼 RN 不会按照你的想法的顺序走的,跳来跳去,双向滚动超级大坑
    iOCZS
        2
    iOCZS  
       1 天前
    相关代码看看?
    jingrui
        3
    jingrui  
       1 天前
    我们还是用的 FlashList ,滚动到指定消息 很难优化


    const firstScrollRef = useRef(false);

    function scrollToMsg(msgID){
    let index = viewMessages.findIndex((value)=>value?.msgID === msgID)
    if (index <= 0) index = 1;
    console.log('scrollToMsg', index, msgID, viewMessages.length);
    flatListRef.current.scrollToIndex({ index:index-1, animated: true });
    }

    const scrollToBottom = useCallback(
    debounce(() => {
    if (flatListRef.current) {
    console.log('scrollToBottom', firstScrollRef.current, from, msgID)
    IMSdk.readConversation(uid)
    if (!firstScrollRef.current) {
    if (from === 'history' && msgID) {
    scrollToMsg(msgID)
    } else {
    flatListRef.current.scrollToEnd({ animated: true });
    }
    firstScrollRef.current = true
    } else {
    flatListRef.current.scrollToEnd({ animated: true });
    }
    }
    }, 200), // 延迟时间可以根据需要调整
    [from, msgID]
    );
    letterLim
        4
    letterLim  
    OP
       1 天前
    const getMessageList = useMemo(() => (startPage: number, endPage: number) => {
    return allMessageList
    .slice(startPage * PAGE_SIZE, (endPage + 1) * PAGE_SIZE)
    }, [allMessageList, PAGE_SIZE])

    useEffect(() => {
    setMessageList(getMessageList(0, 0))
    }, [])

    useEffect(() => {
    if (startPage === 0 && isAtBottom) {
    setMessageList(getMessageList(startPage, endPage));
    }
    }, [startPage, endPage, getMessageList, isAtBottom]);


    const onReachTop = useCallback(() => {
    console.log('onReachTop');
    if (isJumpingToUnread) {
    return;
    }
    if (startPage > 0) {
    const _startPage = startPage - 1;
    setStartPage(_startPage);
    setMessageList(getMessageList(_startPage, endPage))
    }
    }, [startPage, isJumpingToUnread, endPage, getMessageList]);


    const onReachBottom = useCallback(() => {
    console.log('onReachBottom', isJumpingToUnread);
    if (isJumpingToUnread) {
    return;
    }
    if (messageList.length < allMessageList.length) {
    setEndPage(pre => {
    setMessageList(getMessageList(startPage, pre + 1))
    return pre + 1
    })
    }
    }, [messageList.length, setEndPage, startPage, allMessageList.length, isJumpingToUnread, getMessageList]);

    const goUnreadMessage = useCallback(() => {
    setIsJumpingToUnread(true);
    setUnreadNum(0)
    let _messageList: any = []
    const startPage = Math.floor(unreadNum / PAGE_SIZE) > 1 ? Math.floor(unreadNum / PAGE_SIZE) - 1 : 0;
    let endPage = startPage + 1;
    _messageList = getMessageList(startPage, endPage)
    const index = _messageList.findIndex(item => item._id === lastMessageId.current)
    if (index % PAGE_SIZE === 0) {
    endPage = startPage + 1
    }
    setStartPage(startPage);
    setEndPage(endPage);
    setMessageList(_messageList)
    }, [allMessageList.length, getMessageList]);

    useEffect(() => {
    if (isJumpingToUnread && lastMessageId.current) {
    const index = messageList.findIndex(item => item._id === lastMessageId.current)
    if (index !== -1) {
    const timer = setTimeout(() => {
    clearTimeout(timer)
    flatListRef.current?.scrollToIndex({
    index,
    animated: true,
    viewPosition: 0.1,
    })
    }, 200)
    }
    }
    }, [messageList.length, isJumpingToUnread]);


    useEffect(() => {
    if (!lastMessageId.current && allMessageList.length >= (unreadNum-1) && unreadNum) {
    lastMessageId.current = allMessageList[unreadNum-1]?._id;
    }
    }, []);

    useEffect(() => {
    const initMessageList = () => {
    setStartPage(0)
    setEndPage(0)
    setMessageList(getMessageList(0, 0))
    InteractionManager.runAfterInteractions(() => {
    flatListRef?.current?.scrollToOffset({ offset: 0, animated: true })
    })
    }
    EventCenter.on('init_message_list', initMessageList)
    return () => {
    EventCenter.remove('init_message_list', initMessageList)
    }
    }, [getMessageList])


    const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
    const isBottom = event.nativeEvent.contentOffset.y <= 10;
    setIsAtBottom(isBottom);
    }, []);

    const onScrollToIndexFailed = useCallback((info: {
    index: number;
    highestMeasuredFrameIndex: number;
    averageItemLength: number;
    }) => {
    const offset = info.index * info.averageItemLength
    flatListRef.current?.scrollToOffset({ offset: offset, animated: true })
    }, []);

    const threshold = isJumpingToUnread ? 0.1 : 1

    <FlatList
    removeClippedSubviews
    windowSize={20}
    onStartReachedThreshold={threshold}
    onEndReachedThreshold={threshold}
    onEndReached={onReachBottom}
    onStartReached={onReachTop}
    onScroll={handleScroll}
    scrollEventThrottle={17}
    keyboardDismissMode="on-drag"
    maxToRenderPerBatch={10}
    initialNumToRender={10}
    onTouchStart={() => {
    setIsMore(false)
    setEmojiKeyboardVisible(false)
    }}
    onScrollBeginDrag={() => {
    setIsJumpingToUnread(false);
    }}
    maintainVisibleContentPosition={startPage && !isAtBottom ? {
    minIndexForVisible: 1,
    autoscrollToTopThreshold: 10
    }:undefined}
    onScrollToIndexFailed={onScrollToIndexFailed}
    inverted
    contentContainerStyle={{ paddingHorizontal: 10 }}
    scrollsToTop={false}
    data={messageList}
    keyExtractor={item => item._id}
    showsVerticalScrollIndicator
    ref={flatListRef}
    renderItem={renderItem}
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1038 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 19:07 · PVG 03:07 · LAX 11:07 · JFK 14:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.