ReactNativeカテゴリタブ-各タブは異なるカテゴリをレンダリングします
私は現在、ユーザーがScrollViewから特定のカテゴリを選択して、そのカテゴリに関連する投稿をレンダリングできる参照画面を実装しようとしています。
私のAPIはバックエンドからすべての投稿データを取得し、投稿ごとにcategoryIdというパラメーターを呼び出します。
私がやろうとしているのは、たとえば、私のカテゴリの1つがスポーツである場合です。ユーザーが[スポーツ]タブを選択すると、スポーツに関するすべての投稿を含むフラットリストが表示されます。
この現在の実装では、カテゴリタブがあり、タブのいずれかを選択すると、その特定のカテゴリの投稿ではなく、すべての投稿がレンダリングされます。
これが私のコードです:
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>
</>
);
}
console.log(posts)を実行すると、次のようになります。
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,
},
API呼び出しを変更して、IDでカテゴリを取得し、特定のカテゴリごとにすべての投稿を含めることを考えましたが、それは機能しませんでした。そのため、API呼び出しを使用してすべての投稿を取得しました。
更新
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}
私は次のコードを試しましたが、誰かがそれが正しいかどうか教えてもらえますか?
回答
例を挙げると、最初に画面Aのフラットリスト(すべてのカテゴリを表示)のアイテムをクリックしてから、システムを画面B(選択したカテゴリのアイテムのみを表示するフラットリスト)に移動するとします。
通常の方法は、たとえばphpスクリプト(この例ではsjson.php)によって、選択したカテゴリのデータのみを動的に表示することです。
画面Aの場合、次のようになります。
画面GetFlatListItem関数:
GetFlatListItem (fruit_name) {
this.props.navigation.navigate('ScreenB', {unitserial: fruit_name})
}
画面フラットリストは次のようになります。
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>
画面Bの場合、次のようになります。
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);
});
}
フラットリストは次のようになります。
<FlatList
data={ this.state.dataSource }
>
ニーズに合わせてコードを変更する必要があることに注意してください。上記はほんの一例です。
最初に状態を定義する:
const [apiRespPonse, setApiRespone] = useState("");
const [selectedTabData, setSelectedPost] = useState("");
const [category, setCategory] = useState("Sports");
API呼び出しセットで応答:
const fetchAllPost = () => {
setApiRespone([]);
const newArr = apiRespPonse.filter(obj => obj.label===category);
setSelectedPost(newArr)
};
レンダリングオプションでは、配列のフィルターを使用して、選択したタブデータを取得します。
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>
);
};
それが役立つかもしれません。
私が正しく理解していれば、選択したカテゴリでフラットリストのコンテンツを更新したいだけです。更新前のコードは、少しの更新で必要なすべてを実行すると思います。更新する必要があるコードの部分は次のとおりです
{categories.map((e,index)=>(
<TouchableOpacity
...
style={[
...
index===page && {
borderBottomWidth:3,
borderBottomColor:colors.primary,
borderRadius:2,
}]
onPress={()=>{setPage(index)}}
>
...
</TouchableOpacity>
)}
postsApi.getPosts(page);
指定されたpage
パラメータに基づいて正しいデータを返すことを確認してください。