FlatList组件onViewableItemsChanged实现左右列表联动

onViewableItemsChanged简介

FlatList是React Native提供的一个高性能的列表组件,本身具备了列表Item缓存复用的逻辑,并且还支持下拉刷新等功能。在列表开发中,特别是FlatList列表滚动时,需要监听当前那些数据item在可见范围内,这时候就需要用到FlatList的onViewableItemsChanged属性。使用onViewableItemsChanged要与viewabilityConfig绑定使用。

  • onViewableItemsChanged:在可见行元素变化时调用。
  • viewabilityconfig:可见范围和变化频率等参数的配置。

viewabilityconfig常用的配置有如下一些: 在这里插入图片描述 如果不配置viewabilityconfig,viewabilityconfig是有一些默认属性值的。

示例

在左右分类的列表中,我们将向你展示如何onViewableItemsChanged实现可见列表的刷新,效果如下图所示。 在这里插入图片描述 首先,我们使用已经封装好的Axios工具执行数据请求,当然也可以直接使用Fetch工具进行请求,请求方法和参数如下:

async function getGoodCategory() {
        let url = '/product/good/list-all'
        let param = {
            facilityCd: 188,
            prodCatalogCd: 1201,
            showInSelect: '1',
        };
        const data = await apiRequest.post(url,param)
         ....  //省略其他代码
    }
复制代码

按照左右列表的特性,我们需要的数据结构是一个列表嵌套列表的结构,形如:

{
  "data": {
    "content": [
      {
        "id": "SC_188_5",
        "productCategoryId": "GOOD_0",
        "categoryName": "人气热销",
        "categoryImageUrl": "/img/CGV_CMS_1609772871639.png",
        "goodList": [
          {
            "id": "G_188_935",
            "productCd": 22318,
            "productId": "22010322",
            "productName": "PAC虎年拜年礼包5",
            "smallImageUrl": "/img/CGV_CMS_1643181892747.jpg",
            "detailScreen": "PACONNIE虎年拜年礼包",
            "productCategoryId": "GOOD_0",
            "categoryName": "人气热销",
            "price": 88.80,
            "priceWithTax": 106.00,
            "guidePrice": 88.80,
          }
        ]
      }
    ],
    "totalElements": 6
  },
  "code": 200,
  "message": "OK"
}

复制代码

拿到数据后,接下来就是绘制界面,分为左侧的分类列表和右侧的商品列表,核心代码如下:

const GoodListScreen = ({navigation: {navigate}}) => {
    let currentCategoryName
    const sectionListEle = useRef(null)
    const [goods, setGoods] = useState([])
    const [selectedIndex, setSelectedIndex] = useState(0)


    useEffect(() => {
        getGoodCategory()
    }, [])

    async function getGoodCategory() {
        let url = '/product/good/list-all'
        let param = {
            facilityCd: 188,
            prodCatalogCd: 1201,
            showInSelect: '1',
        };
        const data = await apiRequest.post(url,param)
        setGoods(
            (data.content).map(({goodList, ...res}, index) => ({
                ...res,
                isHot: index === 0,
                data: goodList,
            })),
        )
    }

    const select = (index) => {
        if (selectedIndex !== index) {
            setSelectedIndex(index)
            sectionListEle.current.scrollToLocation({
                animated: false,
                itemIndex: 0,
                sectionIndex: index,
                viewPosition: 0,
            })
        }
    }

    const onViewableItemsChanged = (info) => {
        const fisrtViewableItem = info.viewableItems[0]
        if (fisrtViewableItem) {
            const {categoryName} = fisrtViewableItem.item
            if (categoryName !== currentCategoryName) {
                const index = goods.findIndex((c) => c.categoryName === categoryName)
                setSelectedIndex(index)
                currentCategoryName = categoryName
            }
        }
    }

    const createGoodOrder = async () => {
       
    }


    function renderShopCart() {
        return (<ShoppingCartBar
            style={{height:60}}
            amount={0}
            num={0}
            onPressLeft={() => navigate('MyModal', {screen: 'ShopingCartScreen'})}
            onPressRight={() => {
                createGoodOrder()
            }}
        />);
    }

    function renderLeftList() {
        return (<View style={styles.leftList}>
            <FlatList
                data={goods}
                renderItem={({item, index}) => (
                    <Menu
                        item={item}
                        isHot={index === 0}
                        isSelected={index === selectedIndex}
                        select={() => select(index)}
                    />
                )}
                keyExtractor={(item) => item.id}
            />
        </View>);
    }

    function renderRightList() {
        return (<SectionList
            style={styles.rightList}
            ref={sectionListEle}
            onScrollToIndexFailed={() => ({
                index: selectedIndex,
                highestMeasuredFrameIndex: 0,
                averageItemLength: 100,
            })}
            sections={goods}
            renderItem={({item}) => (
                <GoodItem  item={item}/>
            )}
            keyExtractor={(item) => item.id}
            onViewableItemsChanged={onViewableItemsChanged}
        />);
    }

    return goods.length>0 && (
        <View style={styles.contain}>
            <View style={styles.body}>
                {renderLeftList()}
                {renderRightList()}
            </View>
            {renderShopCart()}
        </View>
    )
}

const styles = StyleSheet.create({
    contain: {
        flexDirection:'column',
        flex:1
    },
    body: {
        flex: 1,
        flexDirection: 'row',
    },
    leftList: {
        width: 72,
        backgroundColor: '#FBF8FB',
    },
    rightList: {
        flex: 1,
    },
    title: {
        backgroundColor: '#fff',
        padding: 5,
    },
})

export default GoodListScreen;
复制代码

上面代码最核心的代码是使用了FlatList组件的onViewableItemsChanged实现右侧列表的变化监听,核心代码为:

 const onViewableItemsChanged = (info) => {
        const firstViewableItem = info.viewableItems[0]
        if (firstViewableItem) {
            const {categoryName} = firstViewableItem.item
            if (categoryName !== currentCategoryName) {
                const index = goods.findIndex((c) => c.categoryName === categoryName)
                setSelectedIndex(index)
                currentCategoryName = categoryName
            }
        }
    }
复制代码

当点击左侧的分类列表时,我们会调用Menu组件动的select属性,执行select方法,由于右侧的列表使用了onViewableItemsChanged属性,当收到刷新的通知后就会自动刷新界面。而为了实现滑动右侧的列表,左侧的列表也能够滑动,在onViewableItemsChanged方法中,我们增加了如下的逻辑。

 if (categoryName !== currentCategoryName) {
         const index = goods.findIndex((c) => c.categoryName === categoryName)
          setSelectedIndex(index)
     }
复制代码

到此,左右列表联动的功能就实现了。

おすすめ

転載: juejin.im/post/7075971648343506975