React Native Category Tabs - cada guia renderiza categorias diferentes

Nov 29 2020

No momento, estou tentando implementar uma tela de navegação, onde os usuários podem escolher uma categoria específica de um ScrollView que renderiza as postagens relacionadas a essa categoria.

Minha api obtém todos os dados de postagem do back-end e para cada postagem eu tenho uma chamada de parâmetro categoryId.

O que estou tentando fazer é, por exemplo, se uma das minhas categorias for esportes. quando o usuário seleciona a guia esportes, uma lista plana com todas as postagens sobre esportes deve ser renderizada.

Com esta implementação atual, eu tenho minhas guias de categoria e quando eu seleciono qualquer uma das guias, todas as postagens são renderizadas, não as postagens para aquela categoria específica.

Aqui está o meu código:

function SearchScreen({ navigation }) {
const [posts, setPosts] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);

const loadPosts = async () => {
setLoading(true);
const response = await postsApi.getPosts(page);
setLoading(false);

if (!response.ok) return setError(true);

setError(false);
setPosts(response.data);
};

const[page,setPage]=useState(0);

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

const categories = [
{
  label: "Sports",
  id: 1,
},
{
  label: "Fashion",
  id: 2,
},
{
  label: "News",
  id: 3,
   },
  ];

 const[label,setLabel]=useState('Sports')
 const[dataList,setDataList]=useState(posts)

const setLabelFilter=label=>{
setLabel(label)
}

return (
<>
  <ActivityIndicator visible={loading} />
  <Screen style={styles.screen}>
    {error && (
      <>
        <View style={styles.error}>
          <AppText>Could not retrieve posts from server.</AppText>
          <AppButton title="Retry" onPress={loadPosts} />
        </View>
      </>
    )}
    <ScrollView 
    horizontal 
    style={{flexDirection:"row",
    alignContent:"center",
    width:Dimensions.get('window').width/1.05,
    marginBottom:20,
    }} 
    showsHorizontalScrollIndicator={false}
    >
    {categories.map(e=>(
            <TouchableOpacity 
            style={[
                {paddingHorizontal:10,paddingBottom:10},
                label===e.label && 
                {borderBottomWidth:3,
                borderBottomColor:colors.primary,
                borderRadius:2,
            }
                ]} 
                onPress={()=>setLabelFilter(e.label)}
                >
            <AppText style={[{fontWeight:"500",color:colors.medium},label===e.label && 
{color:colors.primary,fontWeight:"700"}]}>{e.label}</AppText>
            </TouchableOpacity>
    ))}
    </ScrollView>

    <FlatList
      data={posts} // to have all the data
      keyExtractor={(post) => post.id.toString()}
      renderItem={({ item,index }) => (
        <Card
          title={item.title}
          subTitle={item.subTitle}
          onPress={() => navigation.navigate(routes.POST_DETAILS, {post:item,index})}            
  />
      )}
    />
  </Screen>
</> 
);
}

Quando eu faço console.log (postagens), minha resposta se parece com:

Object {
"Category": Object {
  "id": 1,
  "name": "Sports",
},
"categoryId": 3,
"createdAt": "2020-11-18T13:43:19.616Z",
"deletedAt": null,
"id": 506,
"subtTitle": "test",
"title": "test",
"updatedAt": "2020-11-23T06:57:44.150Z",
"userId": 1,
 },

Eu pensei em mudar minha chamada de API para obter a categoria por seu id e incluir todos os posts para cada categoria específica, mas isso não funcionou, então fui com a chamada de API para obter todos os posts.

Atualizar

 const[label,setLabel]=useState('Sports')

 const setLabelFilter=label=>{
setLabel(label)
  }

 const [currentCategoryId, setCurrentCategoryId] = useState()

 const toggleBrands = (categoryId) => {
 setCurrentCategoryId(categoryId)
 setLabel(label)
   };

 return(
 <ScrollView 
    horizontal 
    showsHorizontalScrollIndicator={false}
    >
    {categories.map(e=>(
            <TouchableOpacity 
                key={e.id}
                onPress={()=>{toggleBrands(e.id),
                setLabelFilter(e.label)}}
                selected={e.id === currentCategoryId}
                >
            <AppText>{e.label}</AppText>
            </TouchableOpacity>
    ))}
    </ScrollView>

    <FlatList
      data={currentCategoryId ? 
posts.filter(post=>post.categoryId===currentCategoryId
        ):posts}

Tentei o seguinte código, alguém pode me dizer se está correto ou não?

Respostas

KenLee Nov 29 2020 at 13:20

Para dar um exemplo, digamos que você primeiro clique em um item em uma lista plana (mostrando todas as categorias) na tela A e, em seguida, o sistema será navegado para a tela B (com a lista plana mostrando apenas os itens da categoria selecionada)

O método normal é exibir dinamicamente apenas os dados da categoria selecionada, digamos por um script php (para este exemplo, é sjson.php)

Para a tela A, será assim:

Tela A função GetFlatListItem:

GetFlatListItem (fruit_name) {
   this.props.navigation.navigate('ScreenB', {unitserial: fruit_name}) 
   } 

Tela Uma Flatlist pode ser assim:


          data={ this.state.dataSource }
          
          ItemSeparatorComponent = {this.FlatListItemSeparator}
 
          renderItem={({item}) => 
          
 <View style={{flex: 1, flexDirection: 'row', justifyContent:'flex-start'}}>
<Text  onPress={this.GetFlatListItem.bind(this, item.serial)} > 
          {item.ok}</Text>
</View>
 

Para a tela B, será assim:

const enstring='https://www.test.com/sjson.php?serial=' + this.props.route.params.unitserial ;


       return fetch(enstring)
         .then((response) => response.json())
         .then((responseJson) => {
             

           this.setState({
             dataSource: responseJson
           }, function() {
             // In this block you can do something with new state.
           });
              
              
         })
         .catch((error) => {
           console.error(error);
         });
         }

e a lista plana pode ser como:

<FlatList
       data={ this.state.dataSource }

>

Observe que você precisará modificar seus códigos para atender às suas necessidades. O acima é apenas um exemplo.

RajshekharYadav Nov 29 2020 at 14:07

Primeiro defina os estados:

      const [apiRespPonse, setApiRespone] = useState("");
  const [selectedTabData, setSelectedPost] = useState("");
  const [category, setCategory] = useState("Sports");

Em sua chamada de API, defina a resposta:

const fetchAllPost = () => {
    
    setApiRespone([]);
      const newArr = apiRespPonse.filter(obj => obj.label===category);
            setSelectedPost(newArr)
  };

Para sua opção de renderização, use o filtro de matriz para obter os dados da guia selecionada:

 return (
    <View style={styles.app}>
      <View style={styles.header}>
     
          <View style={{ flexDirection: "row" }}>
         {categories.map((item, index) => {
          return <Text onPress={()=>{
            setCategory(categories[index])
            const newArr = apiRespPonse.filter(obj => obj.label===category);
            setSelectedPost(newArr)
          }} style={styles.title}>{item.label}</Text>;
        })}
        </View>
     
      </View>


<FlatList
data={selectedTabData}/>
    </View>
  );
};

Pode ser que possa ajudar.

SaachiTech Nov 30 2020 at 07:31

Se bem entendi, você deseja apenas atualizar o conteúdo da lista plana com a categoria selecionada. Acho que o código que você tem antes das atualizações faz tudo o que você precisa com pequenas atualizações. Aqui está a parte do código que você só precisa atualizar

{categories.map((e,index)=>(
  <TouchableOpacity 
    ...
    style={[
      ...
      index===page && {
        borderBottomWidth:3,
        borderBottomColor:colors.primary,
        borderRadius:2,
    }]
    onPress={()=>{setPage(index)}}
  >
  ...
  </TouchableOpacity>
)}

Certifique-se de postsApi.getPosts(page);retornar dados corretos com base no pageparâmetro fornecido .