2
respostas

FlatList e atributo: extraData

Bom dia!

Estou estudando react-native e estou tentando criar um jogo que embaralha as cartas ao clicar no botão. Para isso, estou utilizando o shuffle-array, e no FlatList adicionei o atributo: extraData={cards} para escutar o state. Poderiam me ajudar, por favor, a entender o que estou fazendo de errado? Ou o que esta faltando para visualmente as cartas se embaralharem ?

No console.warn ele mostra que as cartas embaralharam, mas visualmente isso não ocorre.

import React, { useEffect, useCallback, useState } from 'react';
import api from '../services/api';
import { 
  SafeAreaView, 
  StyleSheet, 
  FlatList, 
  View, 
  Image,
  Text,
  TouchableOpacity
} from 'react-native';

import suffle from 'shuffle-array';

const CardTable = () => {
  const [ cards, setCards ] = useState([]);
  const [ pathCards, setPathCards ] = useState([]);

  useEffect(() => {
    apiConnect();
  }, []);

  const apiConnect = useCallback( async() => {
    try {
      const response = await api.get('tarot.json');
      const cards = response.data.cards.map(
        (item, index) => ({...item, id: index})
      );
      setCards( cards );      
      setPathCards({ url: response.data.imagesUrl, cardsBack: response.data.imageBackCard })

    } catch (err) {
      console.log("error", err);
    }

  }, 
  [cards, pathCards]) 

  const renderItem = ({item, index}) => (
    <View key={index} style={styles.item}>
      <Image 
        style={styles.cardsImage} 
        source={{uri: pathCards.url + item.image}}
      />
    </View>
  ) 

  const startGame = () => {
    setCards(suffle(cards)); 
    console.warn(cards);
  }

  return (
    <SafeAreaView style={styles.container}>
      <Text style={styles.h1}>
        Jogo de tarot     
      </Text>

      <TouchableOpacity 
        style={styles.buttonStartGame}
        onPress={startGame}
      />

      <FlatList 
        data={cards} 
        keyExtractor={item => item.id}
        numColumns={2} 
        renderItem={renderItem}    
        extraData={cards}
      />  
    </SafeAreaView>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    margin: 10,
    backgroundColor: '#fff',
    alignItems: "center",
  },
  item: {
    alignItems: "center",
    flexGrow: 1,
    margin: 4,
    padding: 10
  },
  cardsImage: {
    width: 120,
    height: 252,       
  },
  h1: {
    fontSize: 40,
    textAlign: "center",
    marginTop: 10,
    marginBottom: 10,
  },
  buttonStartGame: {
    backgroundColor: '#C00',
    borderRadius: 50,
    width:50,
    height:50,
    marginBottom: 10
  }
})

export default CardTable;

Obrigada!

2 respostas

Oi Henrique, tudo bom?

O problema está na hora que vc chama o Shuffle. Atualmente vc está passando direto a variável cards para o método Shuffle, como esse essa variável guarda um Array vc ta passando um um tipo de referência pra essa função. O que acontece nesse caso é que internamente a função de shuffle está manipulando o objeto para fazer a reordenação, mas ela faz isso sem chamar o setCards.

Por isso o React Native não renderiza novamente o seu componente. Quando vc chama o setCards com o retorno da função de shuffle o RN vai ver as diferenças entre o estado atual e o estado que vc está passando para ele e ele só renderiza se tiver alguma mudança. Como o shuffle alterou o estado diretamente o RN não reconhece nenhuma mudança.

Pra Ajustar isso vc precisa passar uma cópia do seu array de cards pra função de shuffle.

setCards(suffle( Object.assign({}, cards) ));

inclusive vc não precisa usar o extra-data