React Native Category Tabs - cada guia renderiza categorias diferentes
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
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.
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.
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 page
parâmetro fornecido .