Web Project/market (client)
Building "My Listed Products" Screen in React Native
hmmmmmmmmmmmm
2025. 5. 11. 19:13
사용자가 판매를 위해 등록한 상품 관리
전체 코드
import AppHeader from "@components/AppHeader";
import { NavigationProp, useNavigation } from "@react-navigation/native";
import BackButton from "@ui/BackButton";
import ProductImage from "@ui/ProductImage";
import size from "@utils/size";
import { runAxiosAsync } from "app/api/runAxiosAsync";
import { ProfileNavigatorParamList } from "app/navigator/ProfileNavigator";
import { getListings, Product, updateListings } from "app/store/listings";
import useClient from "hooks/useClient";
import { useEffect, useState } from "react";
import { FlatList, Pressable, StyleSheet, Text, View } from "react-native";
import { useDispatch, useSelector } from "react-redux";
type ListingResponse = {
products: Product[];
};
export default function Listings() {
const { navigate } = useNavigation<NavigationProp<ProfileNavigatorParamList>>();
const { authClient } = useClient();
const dispatch = useDispatch();
const listings = useSelector(getListings);
const [fetching, setFetching] = useState(false);
const fetchListings = async () => {
setFetching(true);
const res = await runAxiosAsync<ListingResponse>(
authClient.get("/product/listings")
);
setFetching(false);
if (res) {
dispatch(updateListings(res.products));
}
};
useEffect(() => {
fetchListings();
}, []);
return (
<>
<AppHeader backButton={<BackButton />} />
<View style={styles.container}>
<Text style={styles.title}>My Products</Text>
<FlatList
refreshing={fetching}
onRefresh={fetchListings}
data={listings}
contentContainerStyle={listings.length === 0 ? styles.emptyList : styles.flatList}
keyExtractor={(item) => item.id}
ListEmptyComponent={
<Text style={styles.emptyText}>You haven't listed any products yet.</Text>
}
renderItem={({ item }) => (
<Pressable
onPress={() => navigate("SingleProduct", { product: item })}
style={styles.listItem}
>
<ProductImage uri={item.thumbnail} />
<Text style={styles.productName} numberOfLines={2}>{item.name}</Text>
<Text style={styles.productPrice}>₩ {item.price.toLocaleString()}</Text>
</Pressable>
)}
/>
</View>
</>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: size.padding,
},
title: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 15,
},
flatList: {
paddingBottom: 20,
},
emptyList: {
flexGrow: 1,
justifyContent: "center",
alignItems: "center",
},
listItem: {
paddingBottom: size.padding,
},
productName: {
fontWeight: "700",
fontSize: 20,
letterSpacing: 1,
paddingTop: 10,
},
productPrice: {
fontSize: 16,
color: "#666",
paddingTop: 4,
},
emptyText: {
fontSize: 16,
color: "#999",
},
});
코드 상세 설명
1. TypeScript 타입 정의
type ListingResponse = {
products: Product[];
};
서버로부터 받는 응답 데이터의 타입을 정의
상품 정보를 담고 있는 객체의 구조 정의
2. 데이터 Fetching 함수
const fetchListings = async () => {
setFetching(true);
const res = await runAxiosAsync<ListingResponse>(
authClient.get("/product/listings")
);
setFetching(false);
if (res) {
dispatch(updateListings(res.products));
}
};
비동기 함수로 서버에서 상품 목록을 가져오기:
- 로딩 상태를 true로 설정
- API 호출 실행
- 로딩 상태를 false로 설정
- 응답이 성공적이면 Redux 스토어 업데이트
3. useEffect Hook
useEffect(() => {
fetchListings();
}, []);
컴포넌트가 마운트될 때 한 번만 실행되어 초기 데이터를 로드
주요 기능
1. 데이터 로딩 및 상태 관리:
Redux를 통한 전역 상태 관리와 로컬 상태를 조합하여 효율적인 데이터 관리 구현
2. 당겨서 새로고침:
FlatList의 기본 기능을 활용한 사용자 친화적인 데이터 갱신
3. 상품 상세 페이지 이동:
각 상품을 탭하면 상세 페이지로 이동