Home > Net >  React Native FlatList Items Disappearing
React Native FlatList Items Disappearing

Time:05-14

I have a Modal that the user selects categories from, and then that category loads into a FlatList on their profile page. When the first category is selected, it loads properly with the desired formatting:

enter image description here

When the user selects and adds a second item from the Modal, the items disappear, like so:

enter image description here

And when a third item is added, this error is prompted: enter image description here

CODE:

Category array that the user is selecting from, and hook states:

const [catData, setCatData] = React.useState([])
const [catsSelected, setCatsSelected] = React.useState([])

const categoryData=[
    {
        id: 1,
        name: "CatOne",
    },
    {
        id: 2,
        name: "CatTwo",
    },
    {
        id: 3,
        name: "CatThree",
    }]

Function that is called once the user SELECTS the category they want:

const onSelectCategory = (itemSelected, index) => {
        let newData = categories.map(item => {
            if (item.id === itemSelected.id) {
                return {
                    ...item,
                    selected: !item.selected
                }
            }
            return {
                ...item,
                selected: item.selected
            }
        })
        selectedData = newData.filter(item => item.selected === true)
        setCatData(selectedData)
    }
// Note, the above code is as such due to initially wanting the user to be able to select multiple categories at a time, however,
// I've decided that one category at a time would suffice, and I just modified the above function to fit that need (I will tidy it up later).

Function called once user CONFIRMS the category that they've selected:

const catSave = () => {
        if(catData.length > 0){
            if(catsSelected.length < 1){
                setCatsSelected(catData)
            }
            else{
                testData = catsSelected
                testData = testData.push(catData[0])
                setCatsSelected(testData)
            }
        }
        setModalVisible(!modalVisible)
    }

And the FlatList that the selected categories are loaded into:

<FlatList 
   data={catsSelected}
   horizontal
   showsHorizontalScrollIndicator={false}
   keyExtractor={item => `${item.id}`}
   renderItem={renderCats}
                                    
/>

For reference, here is the console log of catsSelected as it is being modified:

[] // when it is initialized
[{"id": 1, "name": "CatOne", "selected": true}] // first item added
[{"id": 1, "name": "CatOne", "selected": true}, {"id": 2, "name": "CatTwo", "selected": true}] // second item added, the FlatList is now invisible
// Error prompts after third item is added.

What I require is for the FlatList to not be invisible, and for this error to not prompt after the third item is added, anyone sure as to why this occurs?

Thanks for the assistance.

CodePudding user response:

Looks like your issue is in the else statement in catSave function. Maybe you want to do this?

const catSave = () => {
        if(catData.length > 0){
            if(catsSelected.length < 1){
                setCatsSelected(catData)
            }
            else{
                setCatsSelected([...catsSelected, catData[0]])
            }
        }
        setModalVisible(!modalVisible)
    }

CodePudding user response:

Issue

  1. You are mutating state
  2. You save the result of Array.prototype.push into state, which is the new array length, not the updated array
  3. On a subsequent render when catsSelected is no longer an array, but a number, the push method doesn't exist

See Array.prototype.push

The push() method adds one or more elements to the end of an array and returns the new length of the array.

const catSave = () => {
  if (catData.length > 0) {
    if (catsSelected.length < 1) {
      setCatsSelected(catData);
    } else {
      testData = catsSelected;              // <-- reference to state
      testData = testData.push(catData[0]); // <-- testData.push mutates state
      setCatsSelected(testData);            // <-- testData now new array length
    }
  }
  setModalVisible(!modalVisible);
}

Solution

Use a functional state update to correctly enqueue an update from the previous stat's array. Shallow copy the previous state's array and append the new data.

const catSave = () => {
  if (catData.length) {
    setCatsSelected(catsSelected => {
      if (catsSelected.length < 1) {
        return catData;
      }
      return [
        ...catsSelected,
        catData[0],
      ]
    });
  }
  setModalVisible(modalVisible => !modalVisible);
}
  • Related