Component not reloading but state is changing with useState

Viewed 2368

I'm not new to react, but im new using hooks, today I was playing with an array of selected elements and selection/unselection.

If they are selected then one icon is shown, if not, another icon (I just change the name prop, not the component itself.

The console.log I do every render shows the right results, but it is not working as expected on the JSX.

The render seems to only reload (Show the right icon) when I unselect. Explaining as a list the procedure and my problem:

  1. All elements come selected
  2. I unselect one element (remove from list), the icon changes.
  3. I select back the element (add to list), the icon don't change.
  4. I unselect another element, then it works and the components are reloaded

Here is my object array:

const dies = [
  {
    id: 1,
    nomDia : 'Dies',
    dataDia : 'previs'
  },
  {
    id: 2,
    nomDia : 'Dies',
    dataDia : 'previs'
  },
  {
    id: 3,
    nomDia : 'Dies',
    dataDia : 'previs'
  }
]

Here is the useSate declaration:

const [diesSeleccionats, setDiesSeleccionats] = useState(dies)

Here is the functions that check if is selected and the function that adds/removes from selected list:

// check if selected
const estaSeleccionat = (dia) => {
    return diesSeleccionats.findIndex((aDia) => aDia.id === dia.id ) != -1
  }
// remove selected or add selected
const gestionarSeleccionats = (dia) => {
    if(estaSeleccionat(dia)){
      return diesSeleccionats.filter((aDia) => aDia.id !== dia.id)
    } else {
      diesSeleccionats.push(dia)
      return diesSeleccionats
    }
 }

Here is the component:

   dies.map((dia) => (
                      <View key={dia.id} style={{flexDirection: 'row', marginTop: 5, alignSelf: 'flex-end'}}>
                        <TouchableOpacity
                          style={{backgroundColor: Colors.llistat1 + 'CC'}}
                          key={dia.id}
                          onPress={() => setDiesSeleccionats(gestionarSeleccionats( dia ))}
                        >
                            <Text style={{fontSize: 18, color: Colors.titolsPantalles}}> {dia.nomDia} </Text>
                        </TouchableOpacity>
                        <TouchableOpacity
                          style={{
                            minWidth: 24,
                            backgroundColor: Colors.llistat1 + 'CC',
                            marginLeft: 5,
                            paddingHorizontal:5,
                            justifyContent:'center', alignItems: 'center'}}
                          onPress={ () => setDiesSeleccionats(gestionarSeleccionats( dia ))}
                          >
                          <Ionicons name={ estaSeleccionat( dia ) ? "md-checkmark" : "md-close"} size={18} color={Colors.titolsPantalles} />
                        </TouchableOpacity>
                      </View>
                    ))

You can see than <Ionicons> name comes defined by if the element is on the selected list.

The log I do every re-render shows the right results. (Boolean of the check function, and the right elements on the array of objects)

Thanks.

1 Answers

I think the issue is related to mutating diesSeleccionats instead of copying it. I think you need to make a copy of it to provide to setDiesSeleccionats so React can analyze the differences and render the correct updated state.

const gestionarSeleccionats = (dia) => {
    const selections = [...diesSeleccionats];
    if(estaSeleccionat(dia)){
      return selections.filter((aDia) => aDia.id !== dia.id);
    } else {
      selections.push(dia)
      return selections;
    }
 }
Related