프로젝트 만들때마다 세팅하는게 귀찮아(...) 자주 쓰는것들 위주로 구성하여 기본설정 한다.
사용하지 않은 것은 직접 빼서 커스텀 하시길.
여기서는 크게 3가지를 설명한다
1. axios 기본설정
2. ui 적용(material-ui, styled-component 사용)
3. cookie를 이용한 authorization 등록 & SSR에서 자동 header에 설정하기
관련 설정 & 코드는 다음 github에 저장되어 있다.
https://github.com/lemontia/react-project-base-config
이번 프로젝트를 설정하면서 사용된 패키지는 다음과 같다
npx create-next-app --example with-typescript [앱 이름]
추가설치
npm i redux react-redux
npm i immer
npm i @types/react-redux
npm i typesafe-actions
npm i next-redux-wrapper
npm i redux-devtools-extension
npm i axios
npm i next-cookies
npm i react-cookies
npm i @types/react-cookies
# UI
npm i styled-reset
npm i babel-plugin-styled-components
npm i @material-ui/core
npm i @material-ui/icons
npm i @material-ui/styles
npm i @material-ui/lab
react, redux, next, typescirpt 의 구체적인 설정방법을 알고 싶다면 이전글 참조
github에서 clone한 후 폴더로 이동, 다음 명령어를 실행한다
# 패키지 다운로드
npm i
# 실행
npm run dev
그럼 기본 포트 3000 번으로 연결해 다음과 같이 실행된다
접속: localhost:3000
1. axios 기본설정
Backend와의 연결은 아직 개발하지 않았는데, 설정은 다음을 참고하면 된다.
config/config.json
{
"development": {
"BACKEND_URL": "http://localhost:10003",
"REDIRECT_URL": "http://localhost:3000",
"IMAGE_URL": ""
},
"production": {
"BACKEND_URL": "http://localhost:10003",
"REDIRECT_URL": "http://localhost:3000",
"IMAGE_URL": ""
}
}
각각 옵션의 설명을 첨부하자면
BACKEND_URL : 백엔드 서버의 URL을 의미
REDIRECT_URL: 프론트엔드에 리다이렉트 할때 사용(소셜 로그인 등 리다이렉트를 받아야할때 사용)
IMAGE_URL: 이미지 URL 의 루트경로
해당 설정을 config/config.tsx 에서 글로벌로 설정한다
const configFile = require("../config/config.json")
const serverEnv = process.env.NODE_ENV
const config = configFile[serverEnv]
export const BACKEND_URL = config["BACKEND_URL"]
export const IMAGE_URL = config["IMAGE_URL"]
export const REDIRECT_URL = config["REDIRECT_URL"]
이것을 이용해 axios 설정을 할 수 있는데 _app.js 에 다음과 같이 했다.
import { BACKEND_URL } from '../config/config'
...
axios.defaults.withCredentials = true;
axios.defaults.baseURL=BACKEND_URL
axios.defaults.timeout=10000
2. ui 적용(material-ui, styled-component 사용)
UI 프레임워크는 material-ui를 사용했다. styled-components 를 쓰고싶다면 material-ui/core/style 을 사용하는 것을 추천한다. (둘다 같이 쓸 수 있지만 그것보단 하나만 쭉 쓰는게 코드 가독성에 좋아보인다.)
material-ui를 쓰고싶지 않다면 제외해도 무방. 또한 bootstrap 으로 바꾸고 싶다면 바꿔 설정하길 추천.
material-ui 는 bootstrap 처럼 UI Framework 이다. 자세한 설명은 다음 홈페이지 참조
material-style은 다음처럼 사용한다.
...
const ContainerMainView = styled(Container)({
padding: "10px 10px"
})
const BoxDiv = styled(Box)({
marginBottom: "10px"
})
...
const Index = () => {
return (
<>
<ContainerMainView>
<BoxDiv>
메인페이지 입니다
</BoxDiv>
...
ContainerMainView에는 padding이 BoxDiv에는 marginBottom이 적용된 것을 확인할 수 있다.
padding이 적용된 것을 확인
개인적으로 이것을 선택한 이유는 디자인 상속이 가능하단 점. 예를들면 다음처럼 설정이 가능하다.
const BoxDiv = styled(Box)({
marginBottom: "10px"
})
// BoxDiv 상속
const BoxViewText = styled(BoxDiv)({
color: "#ff0000"
})
...
return (
<>
...
<BoxDiv>
reducer 테스트:
<BoxViewText>
Input 값: { text }
</BoxViewText>
</BoxDiv>
...
margin-bottom 이 적용된걸 확인할 수 있다.
다만 이대로 설정을 끝내면 새로고침 할때마다 다음 에러가 발생한다.
Prop `className` did not match. Server
이 부분을 해결하기 위해 _document.tsx 에 설정을 했는데, 이전글에 자세히 소개했다.
3. cookie를 이용한 authorization 등록 & SSR에서 자동 header에 설정하기
화면에서 버튼을 누르면 token을 생성해 cookie에 저장하기로 한다. 운영되는 프로그램이라면 token을 backend에서 받아오겠지만 여기서는 backend를 제외했기 때문에 임시로 'aaa'라고 만든다.
화면에 버튼을 추가하고 버튼 핸들러를 등록한다.
...
const TokenArea = styled(BoxDiv) ({
})
...
// 쿠키에 token 저장
const createTokenHandler = () => {
const accessToken = "aaa"; // 본 토큰은 서버에서 받아오도록 해야하지만 여기선 임시로 aaa로 함
axios.defaults.headers.Authorization = "Bearer " + accessToken;
// 만료시간 1일 설정(60초 * 60 * 24)
const expires = new Date()
expires.setDate(Date.now() + 1000 * 60 * 60 * 24)
cookie.save(
'accessToken'
, accessToken
, {
path: '/'
, expires
}
)
dispatch({
type: SET_TOKEN
, payload: {
accessToken: accessToken
}
})
alert("저장되었습니다")
console.log("header: ", axios.defaults.headers.Authorization)
}
...
return (
<>
...
<TokenArea>
<BoxDiv>
<Typography variant={"h6"} className={""}>
Token + cookie 테스트
</Typography>
</BoxDiv>
</TokenArea>
<BoxDiv>
<Button
variant="outlined"
onClick={createTokenHandler}>
토큰 쿠키 저장
</Button>
</BoxDiv>
...
버튼을 누르면 알림창이 나오면서 다음처럼 cookie에 저장, axios header에 추가, 그리고 Redux 에 저장되는 것을 확인할 수 있다.
크롬 개발자도구 => application 창에서 확인 가능한 cookie
console 창에서 보는 axios에 설정된 값.
그러나 새로고침하면 axios와 redux에 저장한 토큰이 리셋된다. 그래서 이것을 SSR에서 설정해주어야 하는데 _app.tsx 에 설정을 추가했다.
...
RootApp.getInitialProps = async (appContext: AppContext) => {
const { ctx } = appContext;
const allCookies = cookies(ctx);
// accessToken를 이용해 고객정보 조회
const accessTokenByCookie = allCookies['accessToken'];
if ((accessTokenByCookie === "" || accessTokenByCookie === undefined) === false) {
axios.defaults.headers.Authorization = "Bearer " + accessTokenByCookie
ctx.store.dispatch({
type: SET_TOKEN
, payload: {
accessToken: accessTokenByCookie
}
})
}
const appProps = await App.getInitialProps(appContext)
return { ...appProps }
}
이제 새로고침해도 cookie의 값을 가져와 axios와 redux에 넣어주는 것을 확인할 수 있다.
실제로 들어갔는지 확인하는 코드를 추가해보자.
...
const {accessToken} = useSelector((state:RootState) => state.userReducer)
...
return (
<>
...
<BoxDiv>
store에 저장된 accessToken => {accessToken}
</BoxDiv>
...
끝.
'공부 > 프로그래밍' 카테고리의 다른 글
[js] video.js 사용하기 (속도조절, 품질 조절 옵션) (2) | 2021.03.26 |
---|---|
[aws] s3 폴더 내 파일 public-read 권한 주기(aws cli 이용) (0) | 2021.03.24 |
[react, material-ui] material-ui style 사용중 SSR 에러 발생(Prop `className` did not match. Server) (0) | 2021.03.19 |
[gradle, springboot] multi project 설정하기 (1) | 2021.03.17 |
[react, next.js] SSR환경에서 access_token, refresh_tokne 관리하기(cookie이용) (2) | 2021.03.12 |
댓글