2. FrontEnd/React / / 2024. 11. 20. 11:25

[ React ] 다국어 코드 중복 제거하는 리팩토링 후기

728x90

다국어 할 때, 중복되는 코드를 단순화하는 작업을 했다

<Box boxShadow={1} borderRadius={1} bgcolor="#fff">
  {termsSelectedLanguage === 'ko' ? (
    !termsContent ? (
      <Loading />
    ) : (
      <Tiptap ref={termsEditorRef} content={termsContent} maxHeight="600px" />
    )
  ) : termsSelectedLanguage === 'en' ? (
    !termsEnglishContent ? (
      <Loading />
    ) : (
      <Tiptap ref={termsEnglishEditorRef} content={termsEnglishContent} maxHeight="600px" />
    )
  ) : termsSelectedLanguage === 'ja' ? (
    !termsJapaneseContent ? (
      <Loading />
    ) : (
      <Tiptap ref={termsJapaneseEditorRef} content={termsJapaneseContent} maxHeight="600px" />
    )
  ) : null}
</Box>;

이 코드를 1차적으로 아래와 같이 리팩토링 했다

// 언어 타입을 명시적으로 정의
type Language = 'ko' | 'en' | 'ja';

const termsContentsMap: { [key in Language]: { content: string; ref: React.MutableRefObject<any> } } = {
  ko: { content: termsContent, ref: termsEditorRef },
  en: { content: termsEnglishContent, ref: termsEnglishEditorRef },
  ja: { content: termsJapaneseContent, ref: termsJapaneseEditorRef }
};

<Box boxShadow={1} borderRadius={1} bgcolor="#fff">
  {(() => {
    const { content, ref } = termsContentsMap[termsSelectedLanguage as Language] || { content: '', ref: null };
    return !content ? <Loading /> : <Tiptap ref={ref} content={content} maxHeight="600px" />;
  })()}
</Box>;

이후, 이것 말고 약관이 3개나 더 있다

계속 같은 코드를 중복적으로 사용하는 현상이 발생한다

type Language = 'ko' | 'en' | 'ja';

const termsContentsMap: { [key in Language]: { content: string; ref: React.MutableRefObject<any> } } = {
  ko: { content: termsContent, ref: termsEditorRef },
  en: { content: termsEnglishContent, ref: termsEnglishEditorRef },
  ja: { content: termsJapaneseContent, ref: termsJapaneseEditorRef }
};
const privacyContentsMap: { [key in Language]: { content: string; ref: React.MutableRefObject<any> } } = {
  ko: { content: privacyContent, ref: privacyEditorRef },
  en: { content: privacyEnglishContent, ref: privacyEnglishEditorRef },
  ja: { content: privacyJapaneseContent, ref: privacyJapaneseEditorRef }
};
const securityContentsMap: { [key in Language]: { content: string; ref: React.MutableRefObject<any> } } = {
  ko: { content: securityContent, ref: securityEditorRef },
  en: { content: securityEnglishContent, ref: securityEnglishEditorRef },
  ja: { content: securityJapaneseContent, ref: securityJapaneseEditorRef }
};

<Box boxShadow={1} borderRadius={1} bgcolor="#fff">
    {(() => {
    const { content, ref } = termsContentsMap[termsSelectedLanguage as Language] || { content: '', ref: null };
    return !content ? <Loading /> : <Tiptap ref={ref} content={content} maxHeight="600px" />;
    })()}
</Box>
<Box boxShadow={1} borderRadius={1} bgcolor="#fff">
    {(() => {
    const { content, ref } = privacyContentsMap[privacySelectedLanguage as Language] || { content: '', ref: null };
    return !content ? <Loading /> : <Tiptap ref={ref} content={content} maxHeight="600px" />;
    })()}
</Box>
<Box boxShadow={1} borderRadius={1} bgcolor="#fff">
    {(() => {
    const { content, ref } = securityContentsMap[privacySelectedLanguage as Language] || { content: '', ref: null };
    return !content ? <Loading /> : <Tiptap ref={ref} content={content} maxHeight="600px" />;
    })()}
</Box>

같은 코드를 세번이나 사용하는게 불필요하다 느껴져

코드를 하나로 만들고 재사용하게 만들었다

type Language = 'ko' | 'en' | 'ja';

const contentsMap = {
  terms: { ko: { content: termsContent, ref: termsEditorRef }, en: { content: termsEnglishContent, ref: termsEnglishEditorRef }, ja: { content: termsJapaneseContent, ref: termsJapaneseEditorRef } },
  privacy: { ko: { content: privacyContent, ref: privacyEditorRef }, en: { content: privacyEnglishContent, ref: privacyEnglishEditorRef }, ja: { content: privacyJapaneseContent, ref: privacyJapaneseEditorRef } },
  security: { ko: { content: securityContent, ref: securityEditorRef }, en: { content: securityEnglishContent, ref: securityEnglishEditorRef }, ja: { content: securityJapaneseContent, ref: securityJapaneseEditorRef } },
};

// 언어를 `Language` 타입으로 명확히 지정
const renderContent = (type: keyof typeof contentsMap, selectedLanguage: Language) => {
  const { content, ref } = contentsMap[type][selectedLanguage] || { content: '', ref: null };
  return !content ? <Loading /> : <Tiptap ref={ref} content={content} maxHeight="600px" />;
};

<Box boxShadow={1} borderRadius={1} bgcolor="#fff">
  {renderContent('terms', termsSelectedLanguage as Language)}
</Box>

<Box boxShadow={1} borderRadius={1} bgcolor="#fff">
  {renderContent('privacy', privacySelectedLanguage as Language)}
</Box>

<Box boxShadow={1} borderRadius={1} bgcolor="#fff">
  {renderContent('security', securitySelectedLanguage as Language)}
</Box>

contentsMap 객체 통합을하고,

중복된 렌도링 로직을 renderContent함수로 만들어서 타입(terms, privacy, secutity)와 언어(termsSelectedLanguage, privacySelectedLanguage,securitySelectedLanguage)를 인자로 받아 맞는 콘텐츠를 렌더링하도록 재사용성을 해서 코드 단순화했다

 

이렇게 코드 줄을 줄일 수 있고, 재사용을 증가하는 방법으로 코드를 클린하게 했다

뿌듯

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유