首页 > 解决方案 > 获取从 FlatList 呈现的项目总数,然后根据项目状态更改更新该数字

问题描述

我对 React Native 非常陌生(老实说,通常是 React/Javascript)并且我很困惑。我有一个家务跟踪应用程序,它使用 Flatlist 呈现家务列表,然后可以使用 React Native Gesture Handler Swipeable 滑动/检查。

我想在杂务列表上方有一个标签,显示已完成的杂务总数(占位符当前显示“??杂务完成”)。我知道这需要找到 1)我的多少 ChoreListItems 是从 Flatlist 组件呈现的,然后 2)这些项目中有多少具有“isComplete”状态。我有几个嵌套/可重复使用的组件,因为这个屏幕会有多个版本(洗衣房、厨房、浴室等),我知道这让我更加困惑。我觉得这里可能有一个明显的答案,但我什至不知道如何开始解包。

这是 ChoreListItem(从 Flatlist 渲染并可以滑动的内容):

import React, { useState, useRef} from 'react';
import { Animated, Image, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import appStyles from '../config/appStyles';
import colors from '../config/colors';
import BodyText from '../config/BodyText';

function ChoreListItem({title}) { 
    const [isComplete, setIsComplete] = useState(false);
    const swipeableRef = useRef();
    //Track interaction occurs on left swipe
    const LeftActions = (progress, dragX) => {
        const scale = dragX.interpolate({
            inputRange: [0, 100],
            outputRange: [0,1],
            extrapolate: 'clamp',
        });
        if (isComplete == false) {
            return (
                <View style ={[appStyles.card, styles.leftActions]}>
                    <Animated.Text style={[styles.swipeText, {transform: [{scale}], fontSize:16, }]}>Swipe to track</Animated.Text>
                    <Image source={require('../assets/control_arrow_right.png')} style={{alignItems:'center',tintColor:colors.baseWhite,}}/>
                </View>
            );
        }
    };
    //Untrack button renders on right swipe
    const RightActions = (progress, dragX) => {
        const scale = dragX.interpolate({
            inputRange: [-100,0],
            outputRange: [1,0],
            extrapolate: 'clamp',
        });
        if (isComplete === true) {
            return (
                <TouchableWithoutFeedback onPress={closeSwipeable}>
                <View style ={[appStyles.card, styles.rightActions]}>
                    <Animated.Text style={[styles.swipeText,{transform: [{scale}], fontSize:16, }]}>Tap to untrack</Animated.Text>
                </View>
                </TouchableWithoutFeedback>
            );
        }
    };
    //Closes swiped action and changes state
    const closeSwipeable = () => {
        if (isComplete===false) {
            setIsComplete (true);
            console.log(title + ' tracked');
        } else {
            setIsComplete(false);
            console.log(title + ' untracked');
        }
    }
    return (
        <Swipeable 
        ref={swipeableRef}
        state={isComplete}
        renderLeftActions={LeftActions} 
        leftThreshold={20}
        rightThreshold={10}
        overshootRight={false}
        renderRightActions={RightActions}
        onSwipeableLeftOpen={closeSwipeable}
        >
            <View style={[appStyles.card, styles.choreListItem]}>
                <BodyText style={{textDecorationLine: isComplete ? "line-through" : "none"}}>{title}</BodyText>
                <Image style={[styles.checkmark, {display: isComplete ? "flex" : "none"}]} source={require('../assets/checkmark_large.png')}/>
            </View> 
        </Swipeable>
    );
}
export default ChoreListItem;
const styles = StyleSheet.create({
    checkmark: {
        width:16,
        height:16,
    },
    choreListItem: {
        paddingLeft:16,
        paddingRight:16,
        paddingTop:20,
        paddingBottom:20, 
        marginBottom:16,
        flex:1,
        flexDirection:'row',
        alignItems:'center',
        justifyContent:'space-between'
    },
    swipeText: {
        color: colors.baseWhite,
    },
    leftActions: {
        paddingLeft:16,
        paddingRight:16,
        paddingTop:20,
        paddingBottom:20,
        marginBottom: 16,
        backgroundColor: colors.primaryBlue,
        flex: 1,
        shadowColor: 'transparent',
        alignItems:'center',
        flexDirection:'row'
    },
    rightActions: {
        paddingLeft:16,
        paddingRight:16,
        paddingTop:20,
        paddingBottom:20,
        marginBottom: 16,
        backgroundColor: colors.primaryPurple,
        shadowColor: 'transparent',
        alignItems:'flex-end',
        flexDirection:'row',
        
    },
});

这是 ChoreList(包括 Flatlist 组件):

import React from 'react';
import {FlatList, StyleSheet, Text, View} from 'react-native';
import appStyles from '../config/appStyles';
import colors from '../config/colors';
import ChoreListItem from '../components/ChoreListItem';
import SectionTitleBar from '../components/SectionTitleBar';

function ChoreList({getCategory}) {
    return (
        <View style={appStyles.containerPadding}>
            {/* <SectionTitleBar title="Today"/> */}
            <View>
                <FlatList
                    data = {getCategory}
                    renderItem={({item}) =>
                        <ChoreListItem title={item.title} />
                    }  
                    keyExtractor={(item) => item.title.toString()}
                />
            </View>
        </View>
    );
}
export default ChoreList;
const styles = StyleSheet.create({
    choreListItem: {
        padding:16,
        marginBottom:16,
    },
});

这是包含所有道具的组件/屏幕:

import React from 'react';
import { Text, View } from 'react-native';
import choreCats from '../config/choreCats';
import choreItems from '../config/choreItems';
import colors from '../config/colors';
import ChoreList from '../components/ChoreList';
import PageHeader_TitleIllo from '../components/pageHeaders/PageHeader_TitleIllo';
import Screen from '../components/Screen';

function LaundryChoresScreen() {
    const choreCategory = choreCats[4];
    return (
        <Screen>
            <PageHeader_TitleIllo 
                category={choreCategory.category}
                image={choreCategory.image}
                bgColor={choreCategory.bgColor}
            />
            <Text style={{padding:8, backgroundColor:colors.blueHueMedium, alignSelf:'flex-start', marginTop: 8, marginBottom: 8}}>?? Chores complete</Text>
            <View style={{backgroundColor:colors.baseFog,}}>
                <ChoreList getCategory={choreItems.filter(({category})=>category=== "laundry")}/>
            </View>
        </Screen>
    );
}

export default LaundryChoresScreen;

标签: javascriptreactjsreact-nativereact-native-gesture-handler

解决方案


有几种不同的方法可以实现这一点,但最好的方法可能是让您将已完成的家务状态提升到与此新功能共享的水平。您可以通过在需要共享的最高位置跟踪完整/不完整的质量来做到这一点。目前,这是您的 LaundryChoresScreen 组件。

然后,您需要将更改您的家务数组的函数传递给ChoreListItem的道具,以便在他们需要更改其家务状态时调用。这个过程称为支柱钻孔。很多人对道具钻探的乏味感到沮丧,并会选择创建一个全局状态来管理应用程序中任何地方的事物(使用ContextsRedux),但对于这种情况来说,这些可能是矫枉过正的。


推荐阅读