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:
When the user selects and adds a second item from the Modal, the items disappear, like so:
And when a third item is added, this error is prompted:
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
- You are mutating state
- You save the result of
Array.prototype.push
into state, which is the new array length, not the updated array - On a subsequent render when
catsSelected
is no longer an array, but a number, thepush
method doesn't exist
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);
}