[TIL NINJA] 21/05/01 헤더 마운트 & 로그인 리다이렉트
window 객체는 서버사이드와 렌더 단에서 사용할 수 없다.
<a onClick={onClickLoginButton}>{window.location}</a>
다음과 같이 에러 발생 !
window객체에서 location을 얻어 전달해야하는 경우.
const onClickLoginButton = () => {
location.current = window.location.href.split(
`${window.location.origin}/`,
)[1];
router.push(
{ pathname: '/login', query: { pathname: location.current } },
'/login',
);
};
다음과 같이 클릭 시 window
객체에 접근해서 location
을 따오도록 한다.
next/link router
vs window.location
- router.patname으로 현재 url 가져올 수 있으나,
/post/161
의 경우/post/[post]
로 값을 가져옴.161
은router.query
에 담겨서 전달됨. 불편... - window.location은 현재 url 그대로 가져온다. ( 내가 원하던거 )
useEffect에서 url값 가져오지 말고, onClick에서 url값 가져오게 한다
현재 로직
헤더의 로그인 버튼을 누르면, 그 때의 url을 쿼리에 넣어서 로그인 페이지로 이동한다.( 페이지 별로 헤더 다시 마운트 됨 , 그래서 useEffect() 내부에서 url 가져와도 되었음. )
문제점
1. 우선 헤더가 계속 새롭게 마운트 되는 것부터 문제. ( 헤더는 페이지별로 달라지지 않으므로 새롭게 마운트 시킬필요가 없다)
2. 같은 페이지에서 쿼리로만 내부 컴포넌트 변경시켜서 렌더링하는 경우 ( url을 갱신 시키지못함. query가 변했으므로 url 갱신 시켜야하는데 그러지 못함)
해결
Header
컴포넌트가 AppLayout
에 있고 AppLayout
을 페이지 별로 부르고있음. 이렇게 하지말고 _app.js
에서 AppLayout
을 불러 헤더는 새롭게 마운트 시키지 않도록 바꾸어야함.
_app.js
const App = ({ Component, pageProps }) => {
const router = useRouter();
/** Google Tag Manager */
useEffect(() => {
const handleRouteChange = (url) => GTMPageView(url);
Router.events.on('routeChangeComplete', handleRouteChange);
return () => {
Router.events.off('routeChangeComplete', handleRouteChange);
};
}, []);
/** Scroll Height Restoration */
useEffect(() => {
const cachedPageHeight = [];
const html = document.querySelector('html');
Router.events.on('routeChangeStart', () => {
cachedPageHeight.push(document.documentElement.offsetHeight);
});
Router.events.on('routeChangeComplete', () => {
html.style.height = 'initial';
});
Router.beforePopState(() => {
html.style.height = `${cachedPageHeight.pop()}px`;
return true;
});
}, []);
const { title = '오즈의 제작소', description } =
pageMetaData[router.asPath] || {};
return (
<>
<Head>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
/>
<style>{fontFace}</style>
{/* Open Graph */}
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content="https://ozjejakso.com" />
<meta
property="og:image"
content="https://ozjejakso.com/image/ogImg.png"
/>
{/* Twitter Card */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@ozjejakso" />
<meta name="twitter:creator" content="@ozjejakso" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:url" content="https://ozjejakso.com" />
<meta
name="twitter:image"
content="https://ozjejakso.com/image/twitCardImg.png"
/>
<title>{title}</title>
<meta name="description" content={description} />
</Head>
<GlobalStyle />
<ThemeProvider theme={Theme}>
<AppLayout>
<Component {...pageProps} />
</AppLayout>
</ThemeProvider>
</>
);
};
<AppLayout>
<Component {...pageProps} />
</AppLayout>
이렇게 _app.js에서 AppLayout으로 감싸면 페이지별로 새롭게 헤더 마운트 안함.
- useEffect가 아닌 onClickHanlder에서 url을 가져오도록함.
내가 원하는 것은 로그인 페이지로 전달되는 쿼리에 url값을 넣어주는 것임. 그렇다면 로그인 버튼을 눌렀을 때! url값을 가져와서 전달해주면 되는것!!
location(url을 담는 변수)를 useRef()로 선언한 이유
location을 useRef 변수로 선언한 이유 : location
값을 onclick
함수내부에서 바꾼다. 이 때 렌더링을 다시 할 필요가 없음. (render()
내부에서 사용하는 변수가 아니라서). 불필요한 렌더링을 막고자 useRef
로 사용하여 선언.
렌더링 될 때마다 새롭게 location
변수를 로드할 필요가 없자나!! 그래서 useRef
로 한거야
useCallback() 복습
메모이제이션된 콜백을 반환합니다.
인라인 콜백과 그것의 의존성 값의 배열을 전달하세요. useCallback은 콜백의 메모이제이션된 버전을 반환할 것입니다. 그 메모이제이션된 버전은 콜백의 의존성이 변경되었을 때에만 변경됩니다. 이것은, 불필요한 렌더링을 방지하기 위해 (예로 shouldComponentUpdate를 사용하여) 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달할 때 유용합니다.
const fun = useCallback(()=>{ console.log(state); },[state])
state가 변경 될 때만 새롭게 함수를 로드시킴. 원래라면 렌더링 할 때마다 컴포넌트 내부에서 선언한 변수 함수 다시 로드하는데 useCallback으로 감싸면 횟수 줄일 수 있다.
**만약 빈 배열이라면 ?**
```javascript
const fun = useCallback(()=>{
console.log(state);
},[])
state가 변경되어도 새로운 state를 참조하지 못하고 처음 함수 로드 되었을 때의 state값만을 참조하게됨. 계속 초기값만 찍힐 것임.
useMemo(() => fn, deps)와 같을까?
같다. useCallback
은 인자로 들어간 함수를 의존성 배열이 변할 때 새롭게 만들어 리턴하는 것이고, useMemo
도 인자로 들어간 함수의 리턴값을 의존성 배열이 변할 때 전달하는 것이라서 그렇다.
Reference
Author And Source
이 문제에 관하여([TIL NINJA] 21/05/01 헤더 마운트 & 로그인 리다이렉트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@rat8397/TIL-NINJA-05-02-헤더-마운트-로그인-리다이렉트저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)