frontend 개발중

front-end+maketing

0%

.env를 github에 넣어버렸다!

.gitignore 파일에 분명히 .env가 있는것을 확인하고 push 했다고 생각했지만 … 확인해보니 github에 기록이 남아있게되었다! 이유를 찾아보니 파일을 생성하기 전 이미 git에 .next를 올렸기 때문에 적용이 되지 않는 것이라고.. 아마 env 를 무시하였으니 그 이유가 아니었을까 다시 한번 더 조심하자고 느꼈다.

[참고사이트1]https://letsgojieun.tistory.com/113

그래서 지금 개발하는 사이트는 api 키와 시크릿 키를 쓰기에 일단 github를 private 처리한뒤에 여러가지 해결 방식을 찾아보았다.

이력 제거 방식 1 필터링 방식

.env파일을 잘못 올린경우 새로운 commit을 올리더라도 commit 히스토리에 남는 것을 지우기 위해서는 전체 히스토리에서 필터링해 제거할 수 있다는 것을 찾게 되었다.

1
$ git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch .env' --prune-empty -- --all

[깃 공식문서 ]https://git-scm.com/docs/git-filter-branch

주의) 로컬 저장소에서도 필터링 되기 때문에 삭제된다.

하지만 벌써 vercel에 공식 배포도 완료해 버려서 수정하려니 계속 컴플릭트가 나서 reset이나 다른 방식으로 해결 방식을 찾고 있다. 엄청 삽질중…

다른 필터링 방식

[참고 사이트 2]https://daily-dev-tips.com/posts/removing-a-env-file-from-git-history/

이 사이트에서는 좀 더 체계적으로 commit 이력을 삭제하는 방법을 알려주었지만 역시 컴플릭트 문제를 먼저 해결해야만 하는 것일까. 일단 deploy 상태인 것을 정지 시키고 새롭게 짜는게 더 빠를지도 모르겠다.. 원본 파일은 있으니 그게 더 빠를 것같기도 하지만 혹시 실제로 이렇게 될 경우를 아주 조금이지만 대비하는 측면에서 조금만 더 살펴보도록 하자

반드시 commit 시 파일 이름 다시 체크할 것!

현재 next.js로 앱 두개를 개발중이며 하나씩 오류를 수정중이며 어떤 오류가 있었는지 그리고 어느 부분에서 고생하였는지 한번씩 기록을 남기려고 한다.

notion api 연동 포트폴리오 사이트

https://github.com/Jeong-hoyun/portfolio-site

배운점

  1. next js의 Image url 파싱할떄 초기 설정이 필요하다는 부분을 배웠다.
    next.config 설정시에 url 의 내용을 파악하고 jpg인지 png인지 혹은 null 일때 처리는 어떻게 해야하는지에 대해서도 한번
    깊게 생각하는 계기가 되었다.
  2. getServerSideProps와 getStaticProps 를 실제적으로 경험하여 SSR과 CSR 의 차이를 어느정도 알게 되었다.
    getStaticProps는 최초 빌드 시에 딱 한 번만 호출된다는 점이 매우 중요한 차이를 만든다는 것을 알수 있게 되었다. 예를 들어 notion api 사용을 한다고 getStaticProps를 사용한다면 notion을 수정한다해도 getStaticProps를 쓴 페이지는 변함이 없다. 반대로 getServerSideProps는 실시간으로 렌더시에 데이터가 수정될 경우에 사전렌더링이 되기 때문에 promise 를 통한 비동기 방식으로 데이터를 받아온다면 실시간 변동도 바로 확인이 가능하다. 왠만하면 수정이 거의 없는 상품 설명서, 또는 제품 목록 등은 SEO를 생각하면 getServerSideProps가 좋지 않을까 생각해본다.
    밑에와 같이 ({ params })과 같은 객체를 넘겨 API주소를 변동시켜서 데이터를 바꿀수도 있기에 다른 방식으로도 써볼 생각이다.
1
2
3
4
5
6
7
8
9
10
11
12
// getStaticProps 페이지 안에서만 쓸수 있다. 
export async function getStaticProps({ params }) {
// API 호출
const response = await fetch(`https/example.com/posts/${params.id}`); //
const post = await response.json();

return {
props: { post }, // 컴포넌트가 전달받을 props 객체
revalidate: false, // 페이지의 Regeneration을 수행하기 위한 유예 기간
notFound: false // 404 페이지 반환 여부 (fallback: false일 때는 불필요)
};
}

에러 사항

  1. cannot find module ‘fs’

    모듈 문제를 한번더 import 한 결과 이와 같은 결과가 나올수 있다는 것을 알았다.

Next.js란

nextjs는 React로 만드는 서버사이드 렌더링 프레임 워크다. 서버사이드렌더링이란 브라우저 혹은 클라이언트에서 실행하지 않고 서버측에서 데이터를 실행하여 모든 js 파일을 로드하고 그 데이터를 웹상에서 먼저 확인 뒤에 사용자는 웹을 보게된다

기존의 react의 구동원리는 클라이언트 사이드렌더링 방식이며 이 경우에는 자바스크립트가 dom을 생성하기 전에는 아무것도 파악되지 않아서 문제를 만들게 되는데 그 문제의 대표적인 문제가 SEO의 부재처리가 될 것이다.

SEO(검색 엔진 최적화)라는 것은 구글의 검색엔진만의 문제가 아닌 대부분의 검색엔진에서 서버사이드렌더링 방식의 데이터만 파싱되기 때문에 검색에 걸리지 않고 그것은 바로 매출에 큰 악영향을 주게 됩니다. 프론트엔드만의 문제가 아닌 회사 전체의 사활이 걸린 문제라고 할 수 있다.

Next.js의 이점

그러한 SEO문제를 NEXT.JS에서는 두가지 방식을 한번에 쓰는 것으로 해결하였습니다.
데이터를 인식하게 할 부분( meta ,description ,keyword etc)은 서버에서 자바스크립트를 로딩하게 하며 ( Server Side Rendering) 비동기적인 부분이나 api를 통해서 새로운 페이지를 불러오는 경우에는 클라이언트 사이드 렌더링(Client Side Rendering)을 통해 빠른 속도로 데이터를 처리하는 것이 nextjs의 큰 이점이라고 생각한다.

또한 프레임워크로서 새로운 기능도 여러 모듈로서 추가되었는데 몇가지만 정리해보려고 한다.

  1. Document기능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Document, { Html, Head, Main, NextScript } from "next/document";
export default class CustomDocument extends Document {
render() {
return (
<Html>
<Head>

</Head>
<body>
<Main />
</body>
<NextScript />
</Html>
);
}
}

html에서 자주 쓰는 Html, Head와 같은 방식으로 서버사이드 방식으로 할 부분을 지정하는 기능이다
모든페이지에 아래 메타테크가 head에 웹 타이틀,ga,meta기능을 추가하여 SEO적인 부분을 크게 보완하였다.

  1. Link 기능

보통 페이지간 이동은 a 태그를 사용하나 next에서는 사용하지 못한다.

a 태그를 사용하면 처음 페이지에 진입시 번들 파일을 받고, a 태그에 의해 라우팅 되면 다시 번들 파일을 받는 것이 문제가 되기에 또한 redux의 경우 store의 state 값이 증발되는 현상도 일어난다. 그렇기 때문에 a 태그는 전혀 다른 사이트로 페이지를 이동시켜 다시 돌아오지 않는 경우만 사용하고, 그 이외에는 모두 Link 태그를 사용합니다.

  1. getStaticProps

페이지에서 (정적 사이트 생성) 이라는 함수 를 내보내는 경우 Next.js는 빌드 시getStaticProps를 통해서 반환된 props를 사용하여 페이지를 미리 렌더링하기 위한 기능이다.
보통 api나 데이터 파싱을 하고 그 데이터를 서버에 남겨 데이터를 SEO에 기여하고 싶을 경우에 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


// 공식문제 예시
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}

export async function getStaticProps() {

const res = await fetch('https://.../posts')
const posts = await res.json()

// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}

export default Blog


function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}


export async function getStaticProps() {

const res = await fetch('https://.../posts')
const posts = await res.json()

// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}

export default Blog

그외에도 더 많은 툴이 존재하지만 다음 기사에 정리해볼 생각이다.

javascript Event를 정리해보자

javascript Event는 매우 방대해서 아직 안써본 기술들이 많았다. 그중에 잘 쓰지 않았던 것들은 한번 정리해보려고 한다.

  1. Event.stopPropagation()
    자바스크립트에서 stopPropagation() 메서드는 event 객체의 버블링을 제거하는데 유용한 메서드이다.
    예를 들어 검색을 하고 클릭을 하는 이벤트를 만들어두었을때 어느 순간에는 클릭만 되게 만들 필요가 있을 것이다. 이벤트 버블링
    와 함께 매우 자주 사용되는 중요한 메서드입니다.

여기서 event 버블링이란 이벤트가 연속하여 발생하는 버블 현상을 의미한다 .이벤트는 이벤트캡쳐링과 이벤트버블링으로 나타나는데 클릭이 발생한 경우를 예로들면 클릭 시점에 해당 위치에서 이벤트가 발생하고 발생하고 다시 겹쳐진 요소를 올라가면서 해당 엘리먼트의 이벤트를 다시 발생시키는 현상을 의미한다.

리엑트 엘리먼트를 통한 방식에서도 유용하게 쓸수 있어보였다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let div=document.createElement('div')
div.innerText='testing'
div.addEventListener('click',()=>{ console.log('test1!') })
document.body.append(div)
let div2=document.createElement('div')
div2.innerText='testing2'
div2.addEventListener('click',()=>{ console.log('test2!') })
div.append(div2)

//VM997:1 test1!
div1을 클릭했을 때는 test1!만 출력
//VM1315:1 test2!
//VM997:1 test1!
div2을 클릭했을 때는 이벤트 버블링 발생 둘다 출력
  1. event.defaultPrevent()

defaultPrevent는 기본적인 html의 기능을 막을 수 있는 메소드이다.체크박스의 클릭 기본 동작,a 태그의 링크 이동 select 선택 기능 전부 다 막을 수 있다. 실질적으로 필요한 경우는 다른 이벤트를 넣었을때 체크박스나 셀렉트와 같은 기본기능이 필요없을 경우에 사용할 수 있지않을까 생각한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
function checkName(evt) {
var charCode = evt.charCode;
if (charCode != 0) {
if (charCode < 97 || charCode > 122) {
evt.preventDefault();
displayWarning(
"영문 소문자만 입력하세요."
+ "\n" + "charCode: " + charCode + "\n"
);
//displayWarning는 경고창을 띄워줌
}
}
}

위의 코드와 같이 영문 소문자만 입력가능하게 세팅을 만들 수도 있다.

Optional chaining

  • 옵셔널체이닝이 유용한 이유

react와 javascript 를 하다보면 값이 TypeError: Cannot read property ‘?’ of undefined
라는 에러를 자주 만나게 된다. 이 방식을 가장 쉽게 해결하는 것이 옵셔널 체이닝이라고 생각한다.
foreach 등을 통해 데이터를 받아올 경우에 값이 안받아올때 undefined를 반환하게 되기때문에 이것이 TypeError를 일으키게된다. map에 일부 데이터만 없다고 해서 못받아오는 경우는 없어야하기 때문에

1
2
3
4
5
6
let temp = obj.first;
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second);
//((obj.first === null || obj.first === undefined)

let nestedProp = obj.first?.second;
//Optional chaining

Optional chaining
위의 함수가 옵셔널체이닝의 기본적인 방식이라고 공식에서 소개하고 있다. 객체에first라는 프로퍼티를 생성하였을때 nestedProp라는 변수에서 obj.first?.second는 결국 temp가 null이나 undefined일 경우 undefined를 반환한다는 뜻이다. 정확하게 변수의 타입을 지정해줘서 TypeError를 회피하는 방식이다.

1
2
3
4
5
6
//현재 에러때문에 옵셔널체이닝 사용한 예시
.then(data => {
// fetch 나 axios와 같은 방식으로 데이터를 받아왔을 경우
const Array= data.response?.docs;
//((data.response === null || data.response === undefined)? undefined : data.response.docs

위와 같은 방식으로 시도중이다

method chaining

메서드가 객체를 반환하게 되면 메서드의 반환 값인 객체를 통해 또 다른 함수를 호출할 수 있다. 이러한 프로그래밍 패턴을 메서드 체이닝(Method Chaining)이라 부른다.

간단한 배열으로 실행하면서 연습중이다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let n='53745'

const result= String(n)
.split('')
.sort()
.reverse()
.join('')

console.log(result)
//순서
//split = 5 3 7 4 5
//sort= 3 4 5 5 7
//reverse=7 5 5 4 3
//join =75545

코드가 엄청간략해지고 편한 측면이 있어보인다.

CORS는 Cross Origin Resource Sharing의 약자로 도메인 및 포트가 다른 서버로 클라이언트가 요청했을 때 브라우저가 보안상의 이유로 대상의 아이피를 차단하는 문제이다

이번에 문제가 된 뉴욕타임즈 api 사용을 한 경우에 발생하여 이번에는 get 방식으로 api 검색사이트를 만들었지만 보안상의 이유와 관리측면에서 post 가 확실히 좋은 방식인 것은 분명하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fetch(URL,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"fq": "romney",
"facet": true,
"begin_date": 20220101,
"end_date": 20220725
}),
// URL(api)에 전달가능한 쿼리를 안보이게 전달
}).then((response) => response.json())
.then((json)=>{
const Array= json.response
const len=docsArray.length
for(let i=0;i<Array;i++){
const myP=document.createElement('p')
myP.innerText=docsArray[i]
document.body.append(Array[i].data)
}})
.catch((error)=>console.log(error))

위와 같은 fetch 방식으로 보내서 해결해보려고 했지만 서버자체의 접근문제라 문제 해결 방식을
찾는데 시간이 조금 필요할것 같다.

1
2
3
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');

서버별로 해결방식은 여러방식이 있었는데 그 전 직장에서 해결했던 방식은 PHP 서버에서의 해결 방식이었다.Access-Control-Allow-Origin: *을 입력해서 모든 도메인을 허용하는 방법이고
* 대신에 특정 url만 허용할 수도 있다.
밑의 내용은 GET, POST, PUT, DELETE, OPTIONS을 허용한다는 의미이다.

노드 방식의 해결 방식도 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
const cors = require('cors');
const domains = ['http://localhost:3000'];
//현재 도메인 지정가능

const corsOptions = {
origin: function(origin, callback){
const isTrue = domains.indexOf(origin) !== -1;
callback(null, isTrue);
},
credentials: true
}
app.use(cors(corsOptions));
//앱에서 사용하여 해결

해결방식을 한번 실행한뒤에 다시한번 내용을 추가 수정할 예정이다

fetch 를 통해서 URL의 데이터를 받는 방식은 여러 방식이 존재할 수 있다.

기본적인 방식으로는 fetch 란 것이 promise 가 내재되어있기때문에
then을 통해서 비동기를 순차적으로 실행할수 있고

1
2
3
4
5
fetch(URL)
.then(res => res.json()) //1번 순서
.then(data => { console.log() } //2번 순서 res.json
.then((e) => { data.response.docs } //2번 순서

물론 asnyc 방식으로 순서를 지정하는 것도 가능하다

1
2
3
4
5
const fetchFunc = async () => {
const res = await fetch(url);
data = await res.json();
data2 = await data.response.docs;
}

아직까지 몇번 써보지 않아서 그렇지만 ajax보다 매우 편리하다!

1
2
3
4
5
6
7
8
let response = await fetch(url);

if (response.ok) { // HTTP 상태 코드가 200~299일 경우
// 응답 몬문을 받습니다(관련 메서드는 아래에서 설명).
let json = await response.json();
} else {
alert("HTTP-Error: " + response.status);
}

HTTP 스테이터스 파악도 간단해서 실질적으로 접속 확인 다중체크 등에 매우 자주 써볼 생각이다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
async function postData(url = '', data = {}) {
// 옵션 기본 값은 *로 강조
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE 등
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data), // body의 데이터 유형은 반드시 "Content-Type" 헤더와 일치해야 함
});
return response.json(); // JSON 응답을 네이티브 JavaScript 객체로 파싱
}

postData('https://example.com/answer', { answer: 42 }).then((data) => {
console.log(data); // JSON 데이터가 `data.json()` 호출에 의해 파싱됨
});

기본적인 URL쿼리를 통한 get 방식은 한계가 있기에 ajax와 마찬가지로 post 방식도 지원한다.
물론 POST방식을 테스트해보니 역시 CORS문제가 나와서 서버관련 문제라 예전에 해결해본 경험이 있으나
까먹었으니 다시한번 해결방법에 대해 정리를 해볼려고 한다

useEffect를 쓰는 이유1

간략하게 설명할 방법은 react가 render를 할때
그 내부에 있는 모든 useState와 기능들이 같이 실행되기 때문에 필요할 경우에만 쓰기위해 필요한 함수를 따로 담아서 쓸수 있는 장점이있다.
약간 promise 비슷한거 같기도 한 느낌

🤔

1
useEffect(()=>OnlyOnce,[])

간략하게 이런식으로 쓰면 한번만 render할때 OnlyOnce라는 함수가 실행되고 실행이 되지 않는다

useEffect를 쓰는 이유2

사실 두번째 이유가 가장 크다
보통 useState와 같이 쓰는데 어떤 이벤트가 발생하였을때 이벤트가 실행될때마다 다른 함수도 자동적으로 실행되는 경우가 많기에 제약을 따로 줄 필요가 있다.

이럴때

1
2
3
4
useEffect(()=> {
if(keyword!==""){
console.log('search',keyword)
}} ,[keyword])

keyword의 값이 변하지 않는다면 console.log(‘search’,keyword) 는 실행되지 않는다. 이와 같은 방식으로 검색앱 등을 만든다거나 어떤 이벤트를 잘 정렬하여서 순서를 만드는 것도 쉽게 가능하다고 생각한다.

react life cycle

get 또는 post로 데이터를 주고 받는 테스트를 하는 도중 너무 많은 에러가 있어
다시 한번 라이프 사이클을 정리하고 비동기를 어디에서 써야할지 변수 선언은 어디서 할지 한번 더 확인하는 겸 글을 정리해보려고 한다. 특히 hook의 useEffect가 이해가 아직 잘 안되서..
💀

-
리액트가 웹 상에 렌더링 되기 위해선 render() 메서드가 실행되어야한다
배운바에 의하면 리엑트는 순서가 정의되어있고 그 순서가 맞지 않으면 실행되지 않는다

  1. Mounting 단계

    컴포넌트가 시작되면(생성자) 우선 context, defaultProps와 state를 저장하는 단계입니다.
  2. componentWillMount

    DOM접근 금지 단계 render하기 전이라서 여러가지 변수 설정이나 변환하기 어려운 단계이다
  3. componentDidMount

    DOM에 접근할 수 있습니다. 그래서 여기에서는 주로 AJAX 요청을 하거나, setTimeout, setInterval같은 비동기 처리가 가능해진다.

-

리액트의 컴포넌트는 생성된 후 Mount 상태에서 한 번 render() 메서드를 실행하고, 후에는 Update 상태에 진입해 shouldComponentUpdate의 값이 true일 때만 render() 메서드를 실행한다

아직 단계를 배우는 중이라서 모르는 부분이나 괜찮은 예시가 있다면 추가할 예정이다