반응형
snowman95
코딩수련장
snowman95
전체 방문자
오늘
어제
  • 분류 전체보기 (229)
    • 앱테크 (3)
    • 옵시디언 (5)
    • 드라마, 영화 (1)
    • 개발자 이야기 (23)
    • 프로젝트 (10)
      • 프로젝트 방법론 (7)
      • 프로젝트 기록 (2)
      • Github (1)
    • 개발 지식 (0)
      • 디자인 패턴 (0)
    • 프론트엔드 개발 (5)
      • 테크트리 (2)
      • React.js (19)
      • ReactNative (2)
      • Next.js (6)
      • GraphQL (6)
      • 패키지 매니저 (2)
      • 라이브러리 (3)
      • 상태관리 라이브러리 (4)
      • Web 지식 (3)
      • HTML CSS (26)
      • Javascript (16)
      • 도구 (Tool) (3)
      • 성능 최적화 (1)
      • 디자인시스템 (0)
    • Python (53)
      • 모음집 (1)
      • 문법 (12)
      • 라이브러리 (15)
      • 알고리즘 (10)
      • 백준 문제풀이 (9)
      • 코딩테스트 (2)
      • 도구 (Tool) (3)
    • C++ (20)
      • 알고리즘 (6)
      • 삼성SW기출 (6)
      • 삼성 A형 (6)
    • 데이터사이언스 (1)
    • 인프라 (9)
      • 하드웨어 지식 (4)
      • Ansible (2)
      • Database (2)
      • 쉘스크립트 (1)
    • 주식 (0)
    • 취업 준비 (4)
      • 취업 이야기 (0)

블로그 메뉴

  • 홈
  • 태그

공지사항

인기 글

태그

  • 백준
  • GraphQL
  • 전공 요약 #운영체제
  • 기계식키보드 #nuphy
  • 알고리즘
  • 오블완
  • 나의 해방일지
  • 삼성SDS
  • nextjs
  • 티스토리챌린지
  • C++
  • 삼성SW역량테스트
  • 언어
  • Next.js #graphql #tailwind.css
  • 전공 요약 #데이터베이스
  • 면접
  • A형
  • 전공 요약 #네트워크
  • 공간복잡도
  • 전공요약

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
snowman95

코딩수련장

리액트에서 외부 링크 관리하기
프론트엔드 개발/React.js

리액트에서 외부 링크 관리하기

2023. 1. 15. 20:15
728x90
반응형

리액트에서 외부 링크를 열어야 하는 경우

당연히 a 테그 만들어서 클릭했을때 열리게 하면 되는거 아니냐~ 라고 생각 하겠지만,

서비스 만들다 보면 엄청 많은 경우의 수가 발생한다.

 

일단 링크의 수가 수십 개가 넘어가면 관리가 안된다.

링크가 자주는 아니더라도 가끔 바뀌더라도 찾아서 변경하는게 여간 귀찮은 일이 아니다.

 

만약에 다른 서비스 안에 들어가는 웹뷰로 서비스를 한다면?

브라우저 창을 열 수 없다.

Iframe 등을 이용해서 우리 서비스 내부에서 링크 내용을 띄워야 한다.

 

공개망 / 사설망 둘다 지원해야하는 서비스라면?

사설망에서는 브라우저를 열 수 없다.  

미리 외부 링크의 문서 내용을 HTML 로 변환해두던가, 내부 서버를 통해 다운로드 받을 수 있게끔 해줘야 한다.

 

 

 

해결 방법

일단 흩어진 링크들을 상수 파일로 가져온다. (예시는 2개 뿐이지만, 실제론 수십 개는 있다고 가정)

// constants/link.ts

export const LINKS = {
    가이드: 'https://...',
    오류신고: 'https://forms/...'
}

export const PRIVATE_LINKS = {
    가이드: `${document.location.origin}/guide/guide.html`,
    오류신고: 'https://forms/...'
}

저 LINKS 를 이용해서 LinkType 을 만들어준다.

export type LinkType = keyof typeof LINKS | undefined

 

 

 

외부 링크를 사용하는 컴포넌트 안에

useOuterLink hook 을 import 해주고 링크 클릭시 openWindow('링크명') 함수를 호출하게 한다.

사설망에서는 PRIVATE_LINKS 사용하고, 그 외에는 그냥 LINKS 상수를 사용하게 제어해줄 수 있다.

// useOuterLink.ts

import { useCallback } from 'react'
import { useTypedDispatch } from './useStore'
import { ENV, isPrivateNetwork } from '@src/constants/env'
import { LINKS, PRIVATE_LINKS } from '@src/constants/link'
import { LinkType, setLinkUrl } from '@src/modules/linkStore'

export const useOuterLink = () => {
    const dispatch = useTypedDispatch()

    const openWindow = useCallback(
        (url: LinkType) => {
            const linkUrl = url ? (url in LINKS ? LINKS[url] : '') : ''

            if (isPrivateNetwork) {
                const linkUrl = url ? url in PRIVATE_LINKS ? PRIVATE_LINKS[url] : '': ''

                const windowFeatures = 'noopener, noreferrer'

                if (linkUrl) {
                    const newWindow = window.open(linkUrl, '_blank', windowFeatures)
                    if (newWindow) {
                        newWindow.focus()
                    }
                }
                return
            }

            if (ENV === '특정 환경') {
                dispatch(setLinkUrl(url))
            } else {
                const windowFeatures = 'noopener, noreferrer'

                if (linkUrl) {
                     const newWindow = window.open(linkUrl, '_blank', windowFeatures)
                    if (newWindow) {
                        newWindow.focus()
                    }
                }
            }
        },
        [dispatch]
    )

    return { openWindow }
}

참고로 저 dispatch(setLinkUrl(url)) 코드는 Redux Store 내부에 외부 링크 url 을 저장한 것이다.

Redux 를 굳이 안써도 된다. 대강 이런 식으로 사용한다고 참고하면 된다.

// modules/linkStore.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { LINKS } from '@src/constants/link'

export type LinkType = keyof typeof LINKS | undefined

interface LinkState {
    linkUrl: LinkType
}

const initialState: LinkState = {
    linkUrl: undefined
}

const linkSlice = createSlice({
    name: 'link',
    initialState,
    reducers: {
        setLinkUrl(state, action: PayloadAction<LinkType>) {
            state.linkUrl = action.payload
        }
    }
})

export const { setLinkUrl } = linkSlice.actions
export default linkSlice.reducer

 

 

그리고 아래와 같이 OuterLinkWindow 컴포넌트를 App.js 같은 신경쓰지 않아도 되는 적당한 위치에 집어넣으면 된다.

이 컴포넌트는 Store에 저장해둔 url 을 가져와서 Iframe 으로 렌더링하는 역할을 한다.

  • iframe 의 스타일은 알아서 추가해주면 된다.
  • FullSizeWindow 컴포넌트는 닫기 버튼을 추가해 둔 것이다.
// OuterLinkWindow.tsx
import { useTypedSelector } from '@src/lib/hooks/useStore'
import { useOuterLink } from '@src/lib/hooks/useOuterLink'
import { LINKS } from '@src/constants/link'
import { FullSizeWindow } from './FullSizeWindow'

export const OuterLinkWindow = () => {
    const url = useTypedSelector(state => state.linkStore.linkUrl)
    const { openWindow } = useOuterLink()

    const linkUrl = url ? (url in LINKS ? LINKS[url] : '') : ''

    return (
        <FullSizeWindow
            isRender={!!linkUrl}
            handleClose={() => openWindow(undefined)}
        >
            <iframe
                title="outer"
                frameBorder={'none'} // border 제거
                src={linkUrl}
            />
        </FullSizeWindow>
    )
}
// App.tsx

return (
  <>
    <OuterLinkWindow />
    <Routes>
      ...
    </Routes>
  </>
)

 

 

그렇게 복잡하지 않게 해결되었다.

동료 개발자들은, 모든 링크가 constants/link.ts 에 정리되어 있고

외부 링크를 추가할 때 a 테그 대신에 hook을 사용한다는 것만 인지하면 된다.

반응형
저작자표시 비영리 동일조건 (새창열림)

'프론트엔드 개발 > React.js' 카테고리의 다른 글

Vite 아직 사용하지 마세요!!!  (2) 2023.01.28
CRA를 Vite로 마이그레이션 하기  (0) 2023.01.15
리액트에서 마우스가 브라우저 창 밖에 있는지 감지하기  (0) 2023.01.15
리액트 장치 유형 감지하기  (0) 2023.01.15
React Query onError 가 동작하지 않는 이슈  (0) 2022.12.21
    '프론트엔드 개발/React.js' 카테고리의 다른 글
    • Vite 아직 사용하지 마세요!!!
    • CRA를 Vite로 마이그레이션 하기
    • 리액트에서 마우스가 브라우저 창 밖에 있는지 감지하기
    • 리액트 장치 유형 감지하기
    snowman95
    snowman95
    (17~19) Unity/Unreal Engine 게임 프로그래머 (20~21) System Administrator ___________ (22~) React 웹 프론트앤드 개발자 __________ 깃헙 : https://github.com/snowman95

    티스토리툴바