Rudson Rodrigues
Rudson Rodrigues

Reputation: 345

React native flatlist multiple selection is not updating

I am using a flatlist to expose all the list of ingredients I have saved on my database, but once I update the state, it is not reflecting on the flatlist component.

The flatlist component

<FlatList
  horizontal
  bounces={false}
  key={ingredientList.id}
  data={ingredientList}
  renderItem={({ item }) => (
    <TouchableOpacity onPress={() => selectedIngredient(item)}>
      <Card key={item.id}>
        <Text key={item.title} style={styles.titleText}>{item.name}</Text>
        <Text key={item.title} style={styles.titleText}>{item.isSelected?'selected':'not selected'} 
        </Text>
        <ImageBackground key={item.illustration} source={item.illustration} style={styles.cardImage}> 
        </ImageBackground>
      </Card>
    </TouchableOpacity>
  )}
  keyExtractor={(item) => item.index}
/>

This is the function that find the selected item "selectedIngredient"

function selectedIngredient(item) {
    console.log('received: ', item.name)
    item.isSelected = !item.isSelected;
    return { ...item.isSelected }
}

That component call is working when I try debbug with console.log after the "item.isSelected = !item.isSelected", but the IU is not updated. Can someone help me to understand how to fix it?

Upvotes: 1

Views: 1363

Answers (1)

Ketan Ramteke
Ketan Ramteke

Reputation: 10675

You need to set state by using either setState in a class-based component or either using useState hook in the functional component.

function selectedIngredient(item) {
    console.log('received: ', item.name)
    item.isSelected = !item.isSelected; //this is not how you set state
    return { ...item.isSelected }
}

Screenshot:

snapshot

here is our old example which I modified for your current scenario:

import React, { useState } from 'react';
import {
  Text,
  View,
  StyleSheet,
  FlatList,
  TouchableOpacity,
} from 'react-native';
import Constants from 'expo-constants';

// You can import from local files

// or any pure javascript modules available in npm

const ingredientList = [
  {
    id: 1,
    name: 'item1',
    selected: false,
  },
  {
    id: 2,
    name: 'item 2',
    selected: false,
  },
  {
    id: 3,
    name: 'item 3',
    selected: false,
  },
  {
    id: 8,
    name: 'item 4',
    selected: false,
  },
  {
    id: 4,
    name: 'item 5',
    selected: false,
  },
  {
    id: 5,
    name: 'item 6',
    selected: false,
  },
];

export default function App() {
  const [selectedItem, setSelectedItem] = useState(null);
  const [allItems, setAllItems] = useState(ingredientList);

  const selectedIngredient = (item) => {
    console.log('selecionado: ' + item.name);
    setSelectedItem(item);
    /* Below operation can be improved by passing index to the function itself.
       so filtering would not be required
     */
    let temp = allItems.filter((parentItem) => parentItem.id !== item.id);
    item.selected = !item.selected;
    temp = temp.concat(item);
    temp.sort((a, b) => parseInt(a.id) - parseInt(b.id));
    setAllItems(temp);
    console.log(allItems);
  };
  return (
    <View style={styles.container}>
      <FlatList
        style={styles.flatlist}
        horizontal
        bounces={false}
        data={allItems}
        renderItem={({ item }) => (
          <TouchableOpacity
            style={styles.flatListItem}
            key={item.id}
            onPress={() => selectedIngredient(item)}>
            <Text>{item.name}</Text>
            {!item.selected ? (
              <Text style={{ color: 'red' }}>{'Not Selected'}</Text>
            ) : (
              <Text style={{ color: 'green' }}>{'Selected'}</Text>
            )}
          </TouchableOpacity>
        )}
        keyExtractor={(item) => item.index}
      />

      {selectedItem ? (
        <View style={styles.selectedTextView}>
          <Text style={styles.selectedText}>{`${selectedItem.name} ${
            selectedItem.selected ? 'selected' : 'not selected'
          }`}</Text>
        </View>
      ) : (
        <View style={styles.selectedTextView}>
          <Text style={styles.selectedText}>{`Nothing selected`}</Text>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  flatListItem: {
    width: 100,
    height: 100,
    backgroundColor: 'white',
    margin: 5,
    borderRadius: 10,
    justifyContent: 'center',
    alignItems: 'center',
  },
  selectedTextView: {
    flex: 8,
    backgroundColor: 'white',
    margin: 5,
    borderRadius: 10,
    justifyContent: 'center',
    alignItems: 'center',
    fontSize: 20,
  },
  selectedText: {
    fontSize: 30,
  },
});

Live Demo

Upvotes: 3

Related Questions