Project/[Project] React DRF Blog

[Frontend] 정리 - 1

bonevillain 2023. 6. 29. 00:33

□ 댓글 Utterances 

Github 저장소를 이용하여 댓글 기능을 구현할 수 있는 앱인데 IT 개발 관련 블로그를 만든다면 큰 도움이 될 것 같다.

(개발자라면 Github 계정 하나쯤은 있을 것이기에.. )

 

Utterances에서는 아래와 같이 각 포스트와 댓글(Issue) 맵핑 방식을 정할 수 있다.

내 포스트와 댓글 맵핑 방식 선택 페이지

보통 맵핑이기에 유일키로 할 수 있는 것으로 정하는데 여기서는 첫 번째 pathname으로 하였다.

문제는 pathname으로 하면 URL에 사용하는 Slug를 조심히 쓰거나 쓰지말아야할 것 같다.

 

Slug 특성 상, 보통 글 제목을 가지고 Slug를 만드는데 백엔드에서 글 제목을 수정할 경우, Slug도 같이 그에 맞춰서 변경하도록 되어있다. 그에 따라서 댓글이 있는 상태에서 글 제목을 수정할 경우, 기존에 있던 댓글들은 맵핑에 실패하여 사라지는 효과를 맛볼 수 있다. 아주 달다.. 아주 달아..

 

이 부분을 해결하기 위해서는 포스트를 조회할 때, Slug 쓰지말고 글 id를 이용하거나 또는 제목은 수정 불가능하게 해야할 것 같다.

 

 

□ useQuery 설정

기본값으로 UseQuery를 사용하게 되면 엄청난 refetch를 마주하게 된다.

잠깐 윈도우를 빠져나갔다가 다시 돌아올때도 refetch하는 것도 볼 수 있다.

 

혼자 개인이 이용하는 블로그 특성 상, 실시간으로 데이터 변화가 많이 없으니 refetch 조건을 조절해주는게 좋을 것 같다.

 

- refetchOnWindowFocus

다른 탭이나 윈도우를 빠져나갔다가 돌아올 때, refetch 하는 것을 막기 위해 전역으로 설정을 해주었다.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnWindowFocus: false,
    },
  },
});

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <Layout>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </Layout>
    </QueryClientProvider>
  </React.StrictMode>,
);

 

- cacheTime

긴 글을 쓴다는 가정 하에 블로그를 한 번 쓰면 1분에 1건 작성하는 것은 아니기에(그만큼 변동되는 경우가 적다) cacheTime은 대부분 Infinity로 두었다. (=같은 요청이면 새로 요청하지 않고 기존 캐시 값 return) 

 

- staleTime

staleTime은 오래된 데이터인지 판단하는 기준이 되는 값인데 이건 각각 설정이 좀 다르다.

카테고리의 경우, 처음 한 번만 불러오면 계속 같은 값을 써도 되기에 Infinity로 두었다. 태그 리스트는 선택된 카테고리에 따라 태그 리스트가 달라지고 포스트 리스트는 카테고리, 태그 선택에 따라 리스트가 달라지기에 적게 또는 별도로 적용하지는 않았다.

 

- enabled

useQuery fetch를 끄고 켜고 하는 기능인데 조건에 따라 실행을 조절할 수 있다. 여기서는 카테고리 정보를 가져올 때는 한 번만 가져오면 되기에 카테고리 리스트를 보유하고 있으면 미동작, 리스트가 비어있으면 동작으로 설정하였다. 태그 리스트의 경우, 카테고리 리스트가 변화할 때만 가져와야하기 때문에 상태 값에 따라 조건을 달리 동작하도록 하였다.

// 카테고리
useQuery('/categories/', fetcher, {
  onSuccess: (data) => {
    setCategories(data.map((category) => ({ ...category, on: false })));
    setTagFetchSwitch(true);
    setPageNum(1);
  },
  enabled: !categories.length,
  staleTime: Infinity,
  cacheTime: Infinity,
});

// 태그
useQuery(
  getSelectedCategories().length > 0 ? `/tags/?categories=${getSelectedCategories()}` : '/tags/',
  fetcher,
  {
    onSuccess: (data) => {
      setTagFetchSwitch(false);
      setTags(data.map((tag) => ({ ...tag, on: false })));
    },
    enabled: TagFetchSwitch,
    cacheTime: Infinity,
  },
);

 

 

 

□ useSessionStorage

포스트 리스트는 2개의 조건에 의해 검색된다. 카테고리 리스트에서 하나를 정하고

 

선택된 카테고리

 

두 번째는 카테고리 내에 존재하는 포스트의 태그 리스트에 의해 포스트 리스트가 결정된다.

 

선택된 태그

 

그런데 이렇게 선택된 조건 아래에서 특정 포스트를 방문했다가 다시 돌아오면 해당 조건들은 전부 초기화되어 있다. 이 부분은 이전에 언급한 useQuery 영향도 있지만 상태보관이 영구적이지 않은 것도 영향을 미친다. 다른 페이지에 방문했다가 포스트 리스트로 돌아오면 모든 상태(state)는 초기화되어 있다.

이 부분을 해결하기 위해서는 다른 방법들도 있겠지만 여기서는 useSessionStorage를 별도로 만들어 계속 상태가 유지되도록 하였다.

const useSessionStorage = (key, initialValue) => {
  const [value, setValue] = useState(initialValue);

  useEffect(() => {
    const item = window.sessionStorage.getItem(key);
    if (item) {
      setValue(JSON.parse(item));
    }
  }, []);

  const setFunction = (newValue) => {
    window.sessionStorage.setItem(key, JSON.stringify(newValue));
    setValue(newValue);
  };

  return [value, setFunction];
};

sessionStorage를 이용하여서 값들을 보관하였는데 localStorage로 바꿔서 써도 큰 문제는 없는 것 같다.

 

hook 초기화의 경우, 아래와 같이 useEffect를 안쓰고 바로 함수로 전달하여 초기화하는 방법도 있다.

const useSessionStorage = (key, initialValue) => {
  const [value, setValue] = useState(() => {
    try {
      const item = window.sessionStorage.getItem(key);

      if (item) {
        return JSON.parse(value);
      }
      window.sessionStorage.setItem(key, JSON.stringify(initialValue));
      return initialValue;
    } catch (error) {
      return initialValue;
    }
  });

  const setFunction = (newValue) => {
    try {
      window.sessionStorage.setItem(key, JSON.stringify(newValue));
    } catch (error) {
      throw new Error('useSessionStorage set function error');
    }
    setValue(newValue);
  };

  return [value, setFunction];
};

 

카테고리와 태그의 경우, 리스트에서 사용자가 어떤 것들을 선택했는지 보관해야하기 때문에 JSON 형태로 데이터를 다룬다. 그런데 sessionStorage는 하나의 문자열만 저장 가능하기에 JSON을 문자열로 변경하여 보관한다.

// 카테고리 정보 fetch 후 선택 여부 정보를 포함하여 저장
setCategories(data.map((category) => ({ ...category, on: false })));

// 태그 정보 fetch 후 선택 여부 정보를 포함하여 저장
setTags(data.map((tag) => ({ ...tag, on: false })));

 

 

 

'Project > [Project] React DRF Blog' 카테고리의 다른 글

[Backend] 정리 - 1  (0) 2023.06.29
Intro.  (0) 2023.06.29