페이지에 돌아왔을 때 스크롤 상태 기억하기

J·2023년 8월 1일
0

todays-recipe

목록 보기
5/9

디테일 페이지 이동 후 브라우저 뒤로 가기를 통해 다시 레시피 페이지로 돌아왔을 때, 리렌더링이 발생해 페이지 초기 상태로 돌아옴.

분류와 소팅을 거친 아이템들의 화면 상태로 되돌아가기 위해 필터링 상태, 소팅 상태, 스크롤 상태의 마지막 위치를 기억해야했음.

기존 코드 기록 및 화면 녹화를 하지 못해 개선한 상태의 코드와 gif 파일만 첨부함.

// useMemoScrollPosition

import { useEffect } from 'react';

// 뒤로 가기 등 타 페이지 방문 후 다시 돌아왔을 때 마지막 스크롤 위치 기억해야하는 페이지에서 사용할 훅

const useMemoScrollPosition = () => {
  // 컴포넌트 마운트 시 이전 스크롤 위치를 기억해 이동하는 useEffect
  useEffect(() => {
    const lastScrollTop = Number(sessionStorage.getItem('scroll_top'));
    if (lastScrollTop) {
      window.scrollTo(0, lastScrollTop);
    }
  }, []);

  // 컴포넌트 언마운트 시 현재 스크롤 위치를 세션에 저장하는 useEffect
  useEffect(() => {
    return () => {
      sessionStorage.setItem('scroll_top', window.scrollY.toString());
    };
  }, []);
};

export default useMemoScrollPosition;
// useRecipeFilters.ts

import { User } from 'firebase/auth';
import { useState } from 'react';

// 레시피 페이지에서 레시피 필터링해주는 hook

const useRecipeFilters = (
  recipeData: Recipe[],
  myIngredients: string[],
  user: User | null
) => {
  // 초기 카테고리
  const initialCategory = () => {
    const savedCategory = sessionStorage.getItem('selected_category_type');
    return savedCategory ? savedCategory : '전체 레시피';
  };

  // 선택된 카테고리 상태
  const [selectedCategory, setSelectedCategory] = useState(initialCategory);

  // 저칼로리 순, 가나다 순 전 기존 정렬 상태
  const [sortType, setSortType] = useState<string>(
    () => sessionStorage.getItem('selected_sort_type') || '기존 정렬 상태'
  );

  // 레시피 분류 선택하기. 세션에 선택한 분류 저장
  const handleCategoryType = (changeCategoryType: string) => {
    setSelectedCategory(changeCategoryType);
    sessionStorage.setItem('selected_category_type', changeCategoryType);
  };

  // 소팅 상태 전환. 세션에 선택한 소팅 상태 저장
  const handleSortType = (changeSortType: string) => {
    setSortType(changeSortType);
    sessionStorage.setItem('selected_sort_type', changeSortType);
  };

  // 내 냉장고 재료들로 만들 수 있는 레시피들
  const canMakeRecipe = (
    recipeIngredients: string,
    myIngredients: string[]
  ): boolean => {
    return myIngredients.every((ingredient) =>
      recipeIngredients.includes(ingredient)
    );
  };

  // 필터링된 레시피 뿌려주기 (나의 냉장고 기능 추가 후 추가 코드 업데이트)
  const filteredRecipes =
    selectedCategory && selectedCategory !== '전체 레시피'
      ? recipeData.filter((recipe: Recipe) => {
          if (selectedCategory === '나의 냉장고' && myIngredients.length > 0) {
            return canMakeRecipe(recipe.ingredients, myIngredients);
          }
          return recipe.type === selectedCategory;
        })
      : recipeData;

  // 나의 재료들로 만들 수 있는 레시피가 없을 때 나타낼 조건부 메시지
  const noRecipeMessage =
    selectedCategory === '나의 냉장고' && filteredRecipes.length === 0
      ? user
        ? '냉장고가 비었거나 냉장고에 보관된 재료들을 전부 포함해서 만들 수 있는 레시피가 없어요. 🫤'
        : '로그인 후 냉장고에 재료들을 넣어주세요. 🫤'
      : null;

  // 저칼로리 순, 가나다 순 소팅 전환
  const sortedRecipes = (recipes: Recipe[]): Recipe[] => {
    if (sortType === '가나다 순') {
      return [...recipes].sort((a: Recipe, b: Recipe) =>
        a.name.localeCompare(b.name)
      );
    } else if (sortType === '저칼로리 순') {
      return [...recipes].sort(
        (a: Recipe, b: Recipe) => parseFloat(a.calorie) - parseFloat(b.calorie)
      );
    }
    return recipes;
  };

  return {
    selectedCategory,
    sortType,
    handleCategoryType,
    handleSortType,
    noRecipeMessage,
    sortedRecipes,
    filteredRecipes,
  };
};

export default useRecipeFilters;

커스텀 훅 코드에 sessionStorage.getItem('selected_sort_type') || '기존 정렬 상태' 등의 코드를 추가해 세션에 필터링, 소팅을 거쳐 나온 상태의 스크롤 위치를 기억하도록 코드를 수정해 기존 레시피 페이지에 훅을 import해서 사용함.

// Recipe.tsx

...
  // 페이지 스크롤 상태 기억: useScrollMemory hook
  useMemoScrollPosition();
...

결과

잘 동작한다 ~_~

profile
벨로그로 이사 중

0개의 댓글