Есть ли более быстрый способ обновления массива json, чем его цикл? - PullRequest
0 голосов
/ 31 марта 2019

Пока 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 записей.Я немного волнуюсь, если список попадет в тысячи строк, это будет действительно плохо.

Есть ли лучший / быстрый / простой / более быстрый способ решить эту проблему?

РЕДАКТИРОВАТЬ

Это функция renderListItem, которая вызывает функцию onPress

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>
    );
};

EDIT # 2 Это код FlatList.

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

Ответы [ 2 ]

0 голосов
/ 01 апреля 2019

Для тех, кто читает, принятый ответ не обновил правильно составленный список на экране. Таким образом, фактический рабочий код для меня ниже. Я уверен, что это потому, что принятый ответ не использовал функцию 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 });
    }
0 голосов
/ 31 марта 2019

я гостю, ваша структура 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
}

Кстати: это не имеет ничего общего с реагировать, правильный дизайн вашего рабочего процесса должен бытьне зависит от библиотеки фреймворков.

Happy Codding !!!

...