Home > Mobile >  array.map doesn't update template with set state of array
array.map doesn't update template with set state of array

Time:03-26

I have this userData state which I use to render a list of notifications - an array of objects - from the user. On the list I've a delete button for each notification which calls a function to handle the update of userData, and remove the notification inside the array to set it's new state. In the end it updates the state with correct data, but on the template it never gets update, in fact it appears to understands that the array is empty... (?).

Instead of entering this if userData.notifications && userData... it enter in the else.

//* const Notifications = () => { **/
//* ... **/
const [userData, setUserData] = useState(null);
const [isLoading, setIsLoading] = useState(true);

// handles delete
const deleteNotifications = (notificationId) => {
  setIsLoading(true);

  const user = {...userData};
  let newUserData = [];

  if(notificationId) {
    newUserData = user.notifications.filter(notification => {
      return notification.notificationId !== notificationId;
    });
  } else {
    user.notifications = [];
    newUserData = user;
  }
 
  setUserData(newUserData);
  setIsLoading(false);
}

// template
  const renderNotifications = () => {

  if(userData.notifications && userData.notifications.length) {
    return (
      <>
        { userData?.notifications?.map(({
            notificationId, 
            sendedAt,
            body,
          }) => (
          <NotificationShadow key={notificationId}>
            <SwipeableView onPress={() => deleteNotifications(notificationId)}>
              <Notification>
                <NotificationHeader>
                  <NotificationText>Nome da Notificação</NotificationText>
                  <NotificationText>{sendedAt}</NotificationText>
                </NotificationHeader>
  
                <ShowMoreText
                  text={body}
                  numberOfLines={2.6}
                  textColor={'#474747'}
                />
              </Notification>
            </SwipeableView>
          </NotificationShadow>
        ))}

        { userData.notifications.length ?
          <DeleteAllContainer onPress={() => deleteNotifications()}>
            <DeleteAllIcon
              type="font-awesome-5"
              name="trash"
              solid
            />
          </DeleteAllContainer> : null }
      </>
    );
  } else {
    return (
      <EmptyDataText>Sem notificações</EmptyDataText>
    );
  }
}

return (
  <StickyHeader title="Notificações">
    <NotificationsContainer>
      {
        isLoading ? <Text>loading...</Text> :
        renderNotifications()
      }
    </NotificationsContainer>

    <AndroidBackHandler onBackPress={() => true} />
  </StickyHeader>
);

//* } **/

I tried to create a state of notification field that belongs to userData object, but it hasn't work. I had also inserted the renderNotifications code directly on the final template return, but... no results.

CodePudding user response:

You were modifying the "shape" of your userData, this should fix it:

const deleteNotifications = (notificationId) => {
    setIsLoading(true);

    let newNotifications = [];

    if (notificationId) {
        newNotifications = userData.notifications.filter((notification) => {
            return notification.notificationId !== notificationId;
        });
    }

    setUserData({...userData, notifications: newNotifications});
    setIsLoading(false);
};

CodePudding user response:

For starters, the declaration of userData concerns me. Lets try to set the initial state to the same type as future states:

const [userData, setUserData] = useState([]);

I am assuming you have something in the beginning of the function that sets the state of userData. But since you added the notification object, the function for delete instead updates userData not with the new data, but with only notifications. This would cause future notifications to not exist, thus creating and empty array. I also don't think that user is all that useful here, since it is just a copy where you read the data from userData, which can also be read from userData without the extra step.

Lets try applying the changes:

if(notificationId && userData) {
  newUserData = userData.filter((user) => {
    return userData.notification.notificationId !== notificationId;
  });
}

If this (with some minor tweaks on your end) doesn't work, you would definitely need to provide more details, especially on the details of your states.

  • Related