Tengo una pantalla de métodos de pago con una lista simple y un botón de acción de eliminación en cada elemento:

const PaymentIndexScreen = ({ navigation }: Props): ReactElement => {
  const [creditCards, setCreditCards] = useState<CreditCard[]>([]);

  useEffect(() => navigation.addListener('focus', () => {
    client.service('credit-cards').find().then((result) => {
      setCreditCards(result.data.map((creditCardData) => {
        const year = creditCardData.expirationDate.slice(2);
        const month = creditCardData.expirationDate.slice(0, 2);

        return {
          ...creditCardData,
          expirationDate: `${month}/${year}`,
          loading: false,
        };
      }));
    });
  }), [navigation]);

  const handleDelete = (selectedCard): void => {
    console.log(selectedCard);
    selectedCard.loading = true;
    Alert.alert(
      'Delete?',
      null,
      [
        {
          text: 'Cancel'
        },
        {
          text: 'Delete',
          onPress: () => client.service('credit-cards').remove(selectedCard._id)
            .then(() => setCreditCards(creditCards.filter((card) => card._id !== selectedCard._id)))
            .catch(handleClientError)
          ,
        },
      ],
    );
  };

  return (
    <ScreenWrapper>
      <ScreenHeader
        title="Payment"
        navigation={navigation}
      />
      <ScrollView>
        <ScreenTitle label="Payment methods" />
        {creditCards.length > 0
          ? creditCards.map((card) => (
            <ListItem
              key={card._id}
              title={`●●●● ●●●● ●●●● ${card.lastDigits}`}
              content={`Expire on ${card.expirationDate}.`}
              onDelete={() => {handleDelete(card)}}
              disabled={card.loading}
            />
          ))
          : (
            <Banner
              iconName="credit-card"
              text="No payment method"
            />
          )}
      </ScrollView>
      <View>
        <Button
          title="Add"
          onPress={() => navigation.navigate('Add')}
        />
      </View>
    </ScreenWrapper>
  );
};

export default PaymentIndexScreen;

La acción de eliminación funciona excepto el cambio de estado de carga .

Parece que cambiar la propiedad card.loading activa cualquier renderizado.

La única solución que veo es reemplazar por completo la matriz creada (como hice para la eliminación) con el elemento actualizado incluido, pero encontré esto muy pesado y podría (¿no?) Conducir a problemas de rendimiento.

¿Cuál es la mejor manera de implementar un estado de carga independiente sin reescribir toda la matriz?

¡Gracias!

0
Soullivaneuh 15 ago. 2020 a las 20:20

2 respuestas

La mejor respuesta

Según el código que pones, me parece que el enfoque para manejar el estado de la lista debe corregirse cuando ocurren algunos eventos. Creo que una posible solución sería abstraerse en una función exclusiva que pueda manejar el estado de cada línea.

Ejemplo (Sandbox):

    const handleData = (item, newState) =>
    setData((prevData) =>
      prevData.map((prevItem) => {
        if (item.index === prevItem.index) return { ...prevItem, ...newState };
        return prevItem;
      })
    );
1
Victor Barros 15 ago. 2020 a las 20:43

React vuelve a renderizar un componente cuando sus accesorios o su estado cambian. En tu caso, ninguno cambia. Tenga en cuenta que para reaccionar a los cambios de activación, el estado / accesorios debe cambiarse de manera inmutable.

En su caso, necesitará usar setCreditCards para cambiar su matriz en su función handleDelete.

setCreditCards(
  creditCards.map(creditCard => {
    if (creditCard._id === selectedCard._id) {
      // return selectedCard with loading set to true
      return {
        ...selectedCard,
        loading: true,
      };
      // Return the card
    }
    return creditCard;
  }),
);

Por lo general, esto no causará un problema de rendimiento a menos que su lista sea muy grande, la complejidad de tiempo es O (n). En ese caso, probablemente considerará la carga diferida o la carga de datos parciales de todos modos.

1
Hassaan Tauqir 15 ago. 2020 a las 17:49