티스토리 뷰

이번 팀 프로젝트 주제는 마켓컬리와 같은 식품 쇼핑몰로 정해졌다

카테고리 버튼을 클릭하여 상품 리스트 페이지에 들어가면 상품 데이터들이 높은 가격 기준으로 정렬된 상태로 가져와야하는데 상품 등록 시 상품 가격 타입을 number로 넣었지만 파이어베이스에서 문자열로 변환되어 등록되어 버린다 문자인 상태에서 orderBy로 정렬하게 되면 유니코드로 정렬이 되기 때문에 원하는 정렬 기준을 맞출 수 없다는 문제가 발생했다

 

내가 하고자 하는 것

상품 가격을 기준으로 오름, 내림 차순을 만들고 싶다


문제해결을 위해 시도한 방법

  1. 파이어베이스로 전체 데이터를 불러온 뒤 sort를 이용해 정렬해 줬다
  2. 이 방법으로 정렬은 가능하지만 클라이언트가 아닌 서버에서 요청값에 정렬을 요청해서 받아야 한다는 피드백을 받고 다시 수정하기로 했다
 {products?.sort((a,b)=>b.price-a.price).map((item) => {
          return (
            <div key={item.productId} className="w-1/4 p-5">
              <div className="h-full flex flex-col justify-between items-center ">
                <img
                  src={item.image}
                  alt="상품이미지"
                  className="w-4/5 h-80 object-cover rounded-md hover:scale-95 transition-all duration-300 cursor-pointer"
                />
                <button className="w-4/5 mt-3 bg-slate-100 flex justify-center items-center text-black py-2 px-4 hover:bg-white rounded-md">
                  <span className="text-xl">담기</span> <LiaCartArrowDownSolid className="ml-2 text-3xl" />
                </button>
                <div className="pt-2 w-4/5">
                  <p className="text-lg font-semibold">{item.title}</p>
                  <div className="flex justify-between items-center mt-2">
                    <div>
                      <p className="text-lg font-semibold">{item.price ? stringTransform(item.price) : null} 원</p>
                    </div>
                    <div className="flex gap-2 items-center">
                      {heart ? (
                        <IoHeartSharp onClick={handleHeart} className="text-3xl text-rose-500 cursor-pointer" />
                      ) : (
                        <IoHeartSharp onClick={handleHeart} className="text-3xl hover:text-rose-500 cursor-pointer" />
                      )}
                    </div>
                  </div>
                </div>
              </div>
            </div>
          );
        })}

문제해결! 

  1. 파이어베이스 공식 문서를 보면 인구수를 기준으로 orderBy를 이용해 정렬하는데 문자로 등록이 된다는 게 아무래도 이상해서 다시 확인해 보기로 했다
  2. input type도 number이고, formData type도 number로 잘 넣어줬는데 왜 여기서 문자로 변형되어 등록되는 걸까? 
  3. 결국 이유는 formData 때문이었다. const price = formData.get('price') as number 여기에서 type를 number로 넣어줘도 formData.get 때문에 문자로 변환되기 때문이다
  4. 명시성을 위해 price = formData.get('price') as number => string 으로 바꿔주고 등록 객체에서 number로 형 변환 후 등록해 주니 파이어베이스에서도 숫자로 등록된 걸 확인할 수 있었다
  5. 상품 가격이 문자로 들어가서 문제였던 부분이 해결되었으니 파이어베이스에서 데이터요청 쿼리에 selectedTab state 값에 따라 정렬 쿼리를 다르게 받고 selectedTab가 바뀔 때마다 데이터를 새로 요청할 수 있도록 의존성 배열에도 담아주면 정렬기능 완성

등록 폼 수정

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    setIsSubmitting(true);
    const key = uuidv4();
    const storageRef = ref(storage, key);

    const formData = new FormData(e.currentTarget);
    const category = formData.get('category') as string;
    const title = formData.get('title') as string;
    const info = formData.get('info') as string;
    const delivery = formData.get('delivery') as string;
    const seller = formData.get('seller') as string;
    const price = formData.get('price') as string;
    const weight = formData.get('weight') as string;

    console.log('확인', typeof price);

    try {
      let image = '';
      if (imageUrl) {
        const data = await uploadString(storageRef, imageUrl, 'data_url');
        image = await getDownloadURL(data?.ref);
      }

      const newProduct = {
        productId: uuidv4(),
        image,
        category,
        title,
        info,
        delivery,
        seller,
        price: Number(price),
        weight,
        createdAt: new Date()?.toLocaleString(),
        quantity: 1
      };

      await addDoc(collection(db, 'product'), {
        ...newProduct
      });
      toast?.success('상품이 등록되었습니다.');
      (e.target as HTMLFormElement).reset();
      setImageUrl('');
    } catch (error: any) {
      console.log(error);
      toast?.error(error.code);
    }

    setIsSubmitting(false);
  };

 

 

데이터 정렬 요청

const [selectedTab, setSelectedTab] = useState(true);
  const [products, setProducts] = useState<ProductType[]>([]);

  useEffect(() => {
    const fetchProductsData = async () => {
      try {
        const querySnapshot = await getDocs(
          selectedTab
            ? query(collection(db, 'product'), orderBy('createdAt', 'desc'))
            : query(collection(db, 'product'), orderBy('createdAt', 'asc'))
        );
        const fetchedProducts: any[] = [];

        querySnapshot.forEach((doc) => {
          const products = doc.data();
          fetchedProducts.push({ ...products, id: doc.id, products });
        });

        setProducts(fetchedProducts);
      } catch (error) {
        console.log('상품 데이터 가져오기 실패', error);
      }
    };

    fetchProductsData();
  }, [selectedTab]);
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함