【问题标题】:Is there a faster way to update a json array than by looping through it?有没有比循环遍历更快的方法来更新 json 数组?
【发布时间】:2019-03-31 11:27:31
【问题描述】:

直到 expo 允许我使用 Realm 数据库,我决定使用 Json 和 asyncstorage。无论如何,源数据都来自 Json,因此对于这个应用程序,将其保留为 json 是有意义的。

我有一个显示 json 的平面列表。列表中每个项目的左侧是一个星形图标。

当我触摸列表中的每个项目时,星号将变为实心表示它已被按下。再按一下,图标会变成星形轮廓,表示已取消选择。

onpress 函数看起来像这个符号是 JSON 数据的名称 JSON 数据有 3 个键...符号、名称和图标名称。符号是平面列表中被触摸的项目。

onPressListItem = ( symbol ) => {
    for (var i = 0; i < this.state.symbols.length; i++){
        if (this.state.symbols[i].symbol === symbol){
            const copyOfSymbolsList = [...this.state.symbols];
            if (copyOfSymbolsList[i].iconName === 'md-star') {
                copyOfSymbolsList[i].iconName = 'md-star-outline';
            } else {
                copyOfSymbolsList[i].iconName = 'md-star';    
            }

            this.setState({ symbols:copyOfSymbolsList });
        }
    }
}

正如您在上面看到的,它基本上只是滚动整个 json 数组以找到合适的行,然后复制列表,更改数据,然后再次设置状态。

在我的像素 2 上的图标更改之前,该应用程序不是超级快,可能延迟半秒,并且列表中只有 100 条记录。如果列表进入数千行,我有点担心它会非常糟糕。

有没有更好/更快/更简单/更具反应性的方法来解决这个问题?

编辑

这是调用 onPress 函数的 renderListItem 函数

renderListItem = ({ item }) => {
    return (
        <TouchableOpacity
            onPress={() => this.onPressListItem(item.symbol)}
        >
            <View style={{flex: 1, flexDirection: 'row'}}>
                <View style={{backgroundColor: 'powderblue'}}>
                    <Ionicons style={styles.listItemIcon} name={item.iconName} />
                </View>
                <View style={{backgroundColor: 'skyblue'}}>
                    <Text style={styles.listItem}>
                        {item.name.toUpperCase()} {item.symbol}
                    </Text>
                </View>
            </View>
        </TouchableOpacity>
    );
};

编辑 #2 这是 FlatList 代码。

<View style={styles.mainContainer}>
                <FlatList
                    data={this.state.symbols}
                    keyExtractor= {(item, index) => item.symbol}
                    ItemSeparatorComponent={this.renderListSeparator}
                    renderItem={this.renderListItem}
                />
            </View>

【问题讨论】:

  • 你是怎么得到这个功能的?没有办法引用被按下的确切项目吗?
  • 我已经通过调用 onpress 函数编辑了问题
  • 返回 JSX 的函数是一个组件。您应该创建自己的列表项组件,该组件接受每个项目的成员作为道具。然后,在该组件中,根据 icon 属性有条件地渲染图标。现在,您不会在每次更改一项时都重新渲染整个列表。

标签: javascript node.js json react-native expo


【解决方案1】:

我客你的json结构是这样的。

  the_data =  [
     {'iconName': 'xxx', 'symbol': '<i class="fa fa-items"></i>'}
    ]

您可以通过索引访问此结构,将索引传递给 onPressListItem 函数。

renderListItem = ({ item }, index) => {
    return (
        <TouchableOpacity
            onPress={() => this.onPressListItem(index)}
        >
            <View style={{flex: 1, flexDirection: 'row'}}>
                <View style={{backgroundColor: 'powderblue'}}>
                    <Ionicons style={styles.listItemIcon} name={item.iconName} />
                </View>
                <View style={{backgroundColor: 'skyblue'}}>
                    <Text style={styles.listItem}>
                        {item.name.toUpperCase()} {item.symbol}
                    </Text>
                </View>
            </View>
        </TouchableOpacity>
    );
};

通过这种设计,您不必迭代您的 json。

onPressListItem = ( index ) => {
   the_dataobj = the_data[index];
   the_dataobj.iconName = 'md-start';
   if (the_dataobj.iconName === 'md-start'){
     the_dataobj.iconName = 'md-start_outline';
   }
   //you don't need a extra else here, is in-necesarry
   the_data[index] = the_dataobj;
   //set state ... do more
}

顺便说一句:这与 react 无关,您的工作流程的正确设计应该独立于框架库。

编码愉快!!!

【讨论】:

  • 感谢您的回答,但我收到一个错误提示索引未定义???
  • 找到了...应该是 renderListItem = ({ item , index}) => {
【解决方案2】:

对于那些正在阅读的人,接受的答案没有在屏幕上正确更新呈现的列表。所以我的实际工作代码如下。我很确定这是因为接受的答案没有使用 this.setState 函数将值写回数组。

另外 if then else 需要在其中包含一个 else,因为当用户点击同一行两次时,我希望它反转其更改。

话虽如此,更新仍然很慢。与在问题中使用 for 循环时的速度大致相同。不知道为什么。

onPressListItem = ( index ) => {
        const copyOfSymbolsList = [...this.state.symbols];
        thePressedSymbol = copyOfSymbolsList[index];

        if (thePressedSymbol.iconName === 'md-star') {
            thePressedSymbol.iconName = 'md-star-outline';
        }else{
            thePressedSymbol.iconName = 'md-star';
        }
        copyOfSymbolsList[index] = thePressedSymbol;
        this.setState({ symbols:copyOfSymbolsList });
    }

【讨论】:

    猜你喜欢
    • 2022-08-05
    • 2021-01-08
    • 2018-12-12
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多