2주차의 워크북 내용은 1주차에 제작했었던 html, css에 기능을 추가하는 것이었다.
나는 배너 화면이 자동으로 넘어가도록 하는 swiper 기능을 직접 js로 구현하기로 했다. 사실 Swiper를 사용하면 되지만… 그러면 딱히 하는 것이 없으므로 직접 구현을 도전했다.
하지만.. 이건 잘못된 선택이었을지도…?
JS 코드

트러블 슈팅
-
for문 내부에서 bannerList[i] 출력시 모든 리스트 내용 한번에 출력
해결? -> 알고보니 그냥 빠르게 로직이 돌아가서 한번에 출력한 것 처럼 보인 거였음…ㅎ
-
view로 변경했던 것을 다시 non-view로 변경하기
해결 -> bannerList를 i -1로 출력하여 replace를 view를 non-view로 변경하게 했다.
-
무한루프 만들기
이미지 변경을 무한루프로 만들려고 했다.
j 변수를 새로 생성했다. j는 i를 5로 나눈 나머지 값이다.
bannerList를 i가 아닌 j로 하여, 나머지가 0,1,2,3,4 다시 0,1,2,3,4 …로 돌아가기 때문에 인덱싱할 변수를 j로 한다.
하지만 그럼에도 무한루프로는 만들지 못했다… → 완벽하게 문제 해결 못함 ㅜ
-
첫번째 루프가 돌고 난 후, 마지막 이미지 non-view 안됨
i의 값이 0이 아니고 j의 값이 0일때, bnnerList[4] 값을 replace하여 view를 non-view로 변경하였다!
j의 값이 0이라는 것은 i의 값이 0,5,10 … 이라는 것이다. 이때, i는 0일때는 첫 시작이므로 non-view의 값이 view로 잘 변경되고 다시 non-view로 잘 변경된다.
하지만 i가 5,10…의 값들은 j의 값이 0인데, bannerList[0-1]이 되므로 -1을 인덱싱하면 에러가 발생하게 된다.(-1을 인덱싱할 수 없어서!)
따라서 i의 값이 0이 아니면서 j의 값이 0일때, bannerList[4]를 view를 non-view로 변경시켜준다!
-
setTimeout 시간을 2000이상으로 변경시 루프 오류
이미지가 변경되는 시간을 조금 더 길게 주기 위해서 7000으로 변경했더니 갑자기 빠르게 루프가 돌면서 이상해졌다…
정확한 에러 원인을 잘 모르겠어서 해결하지 못했다…ㅜ
Failed to load resource: the server responded with a status of 400 ()
종합소감
이번에 기능을 구현하려고 하면서 느낀 점은… 자바스크립트 공부를 더 열심히 해야 겠다는 것이었다.
현재의 나는 이론은 아는데 활용을 전혀 못하고 있는 상태라고 느꼈다. 이게.. 개발을 하면서 확 느껴지니까 굉장히 내 자신이 답답하더라..
강의로 공부하면 해당 강의를 보고 코드를 따라서 작성하니까, 이론은 이해를 하지만 실제로 혼자서 적용하려니까 엄청 애를 먹었다..
그래서 내린 결론은, 중간고사 끝나면 자바스크립트 코테 문제들을 풀어볼까 생각중이다. 일단 문제를 풀면 어떻게 사용할 지 혼자서 생각하게 되니까 도움이 되지 않을까 싶다…!
그리고 또 느낀 점은.. 자바스크립트 공부 괜히 미뤄뒀다가 막판에 고생하는구나..를 느꼈다.. 약간 무서운..? 느낌이 들어서 미룬 경향이 없지않아 매우 많은데..^^… 괜히 미뤘다. 진작할 걸.. 엄청 후회된다악!
그러니 지금 부터라도 열심히 달린다. 이번 2023년 갈려보즈아!
Hook
19년도 이전에는 함수형 컴포넌트는 state와 라이프사이클을 지원하지 않았다. 그렇기에 클래스형 컴포넌트를 많이 사용했지만 React v16부터 Hook을 통해 state와 라이프사이클 관리가 가능해지면서 공식적으로 함수형 컴포넌트 사용을 권장하기 시작했다.
Hook은 useState를 사용해서 state를 관리할 수 있고, useEffect를 사용해서 라이프사이클을 관리할 수 있다.
Hook은 React 내부에 있는 API이기에 별도로 라이브러리를 설치하지 않아도 된다.
useState
class component의 state를 대체 할 수 있다.
Class Component
export default class Example1 extends React.Component {
state = { count: 0 };
render() {
const { count } = this.state;
retrun(
<div>
<p>You clicked {count} times</p>
<button onClick={click}>Click me</button>
</div>
);
}
click = () => {
this.setState({ count: this.state.count + 1 });
};
}
Function Component
useState를 사용해서 function component 안에 특정 값을 state처럼 사용하기
export default function Example2() {
const [count, setCount] = React.useState(0);
retrun(
<div>
<p>You clicked {count} times</p>
<button onClick={click}>Click me</button>
</div>
);
function click() {
setCount(count + 1);
}
}
useState()안의 인자가 class 컴포넌트의 count: 0 과 같은 초기값이다. 따라서 인자로 0을 넣어준다.
React.useState(0)를 한 결과물은 배열이다. 배열의 앞 인덱스는 useState의 0, state(count)가 업데이트 됐을 때, 변경된 값을 의미한다. 즉, 앞 인덱스는 count를 작성하면 된다.
두번째 인덱스는 count를 바꾸는 함수를 제공한다. 따라서 우리는 함수 이름을 setCount라고 명한다.
클릭을 했을 때, setCount가 호출되도록 한다. setCount는 클릭시, count 값이 증가하는 로직을 작성한다.
setCount가 하는 역할은 count의 값을 변경하는 것 + Example2 함수를 다시 실행하는 것이다.
변경한 값을 적용하고 해당 값에 다시 값을 추가해야 하므로, 해당 함수를 다시 실행하기 때문이다.
-
useState를 객체를 사용하는 것으로 변경하기
현재는 useState ⇒ count
로 작성했지만 useState ⇒ { count: 0 };
로 변경해본다.
class component의 state객체 처럼 사용하는 것과 유사하다.
useState의 초기값으로 0이 아닌 state 객체를 넣어준다. { count: 0 }
인덱스 첫번째 부분은 count가 아니라 state
라고 부른다.
setCount 또한 이름이 정해진 것이 아니고, 우리가 의도를 담아서 이름을 지을 수 있기 때문에 setState
라고 변경한다.
이제는 count가 아닌 state.count
로 변경한다.
export default function Example2() {
const [state, setState] = React.useState({ count: 0 });
retrun(
<div>
<p>You clicked {state.count} times</p>
<button onClick={click}>Click me</button>
</div>
);
function click() {
setState({ count: state.count + 1 });
}
}
setState에 들어오는 인자가 this.setState와 같이 객체로도 들어올 수 있다. 기존 state 값에 의존적으로 변경하고 싶다면 객체가 아니라, 함수를 하용할 수 있다.
state를 받아서 새로운 state를 return하는 형식으로 작성한다.
export default function Example2() {
...
function click() {
setState(state => {
return {
count: state.count + 1,
}
})
}
}
해당 방식으로 사용하는 것은 중요하다. 추후에 setState만 사용하는 것이 아니라, setState가 어떤 것을 의존해서 사용하고 있는지 중요해진다. 간단하게 말하자면 의존적으로 state를 처리하지 않게 되기 때문에.. (나중에 이게 굉장히 중요해지는 듯) 해당 방식을 필히 이해해야 한다.
useEffect
라이프 사이클 훅을 대체할 수 있다. 다만, 대체 할 수 있다는 것이지 동등한 역할을 한다는 것은 아니다.
useEffect는 여러가지 기능이 있는데 componentDidMount, componentDicUpdate, componentWillUnmount 라이프 사이클 훅을 대체할 수 있다.
Class Component
최초의 render가 발생한 직후에 componentDidMount를 구현
export default class Example1 extends React.Component {
state = { count: 0 };
render() {
const { count } = this.state;
retrun(
<div>
<p>You clicked {count} times</p>
<button onClick={click}>Click me</button>
</div>
);
}
// 최초의 render가 된 직후
componentDidMount() {
console.log('componentDidMount', this.state.count);
}
componentDidUpdate() {
console.log('componentDidUpdate', this.state.count);
}
click = () => {
this.setState({ count: this.state.count + 1 });
};
}
최초 접속시 componentDidMount 0 출력
버튼 클릭 시 componentDidUpdate 1 숫자 증가
Function Component
export default function Example2() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
conosle.log('componentDidMount & componentDidUpdate', count);
});
retrun(
<div>
<p>You clicked {count} times</p>
<button onClick={click}>Click me</button>
</div>
);
function click() {
setCount(count + 1);
}
}
최초 접속 시, componentDidMount & componentDidUpdate 0 출력
버튼 클릭 할 때마다 componentDidMount & componentDidUpdate 1 숫자 증가
React.useEffect는 componentDidMount일 때에도 실행되고 componentDidUpdate일 때에도 실행된다.
-
React.DenpendencyList 추가
두번째 인자는 React.DenpendencyList로, 배열이다.
React.useEffect(() => {
conosle.log('componentDidMount & componentDidUpdate', count);
}, []);
두번째 인자를 추가하면 최초 접속시 0은 잘 출력되지만, 클릭을 해도 콘솔은 출력되지 않는다.
두번째 인자가 없을때는, 항상 render가 된 직후에는 무조건 저 화살표함수(console.log…)를 실행하라는 의미이다.
두번째 인자로 빈 배열을 넣으면, 최초에만 실행이 된다고 선언된다.
배열 안의 값으로 인해 return(render) 될 때, 직후에 useEffect를 실행하라는 역할로 사용된다. 현재 배열 안에는 아무 값도 없기 때문에 어떤 것에 의해서 render가 되더라도 해당 함수는 최초 말고는 다시 실행되지 않는 것이다.
React.useEffect(() => {
conosle.log('componentDidMount', count);
}, []);
따라서, 엄밀히 말하자면 해당 코드는 componentDidMount & componentDidUpdate가 아닌 componentDidMount인 것이다.
-
useEffect 여러개 사용
useEffect는 여러개 사용이 가능한데, 두개 이상이 존재한다면 순차적으로 실행된다. 따라서 dependecy에 맞는 것일 때만, 안의 함수를 실행한다.
// 최초 한 번만 실행
React.useEffect(() => {
conosle.log('componentDidMount')
}.[])
// 최초 한 번 + count가 업데이트 될 때만 실행
React.useEffect(() => {
conosle.log('componentDidMount & componentDidUpdate', count)
},[count])
count에 dependency가 있다는 건 count가 변했을 때만 render가 업데이트 된 것에 의해서 useEffect가 실행된다는 것이다.
-
componentWillUnmount 역할
useEffect 안의 함수가 새로운 함수를 return하도록 한다. 최초 render가 된 직후, 다음 dependency에 의해서 함수가 실행되기 직전에 return을 실행하고 console이 실행된다.
따라서 return 부분이 componentWillUnmount의 역할이다.
React.useEffect(() => {
conosle.log('componentDidMount', count);
return () => {
// cleanup
// componentWillUmount
};
});
-
useContext
추후에 따로 정리하도록 한다.
분명 28일까지만 해도 잘 포스팅이 되던 블로그가.. 갑자기..! 포스팅이 안됐다 ㅜ..
그간 알고 있던 해결법은 추측하기로는 github blog의 서버 시간이 미국 시간인 것 같아서 새벽에 포스팅을 하면 항상 일자를 전날로 했었다. 그러면 에러없이 잘 올라갔었다.
그런데…? 이렇게 날짜를 바꿔도 업로드가 안되는 것이다..! 오타가 났는지.. 파일 위치를 잘 못 했는지.. 아무리 봐도 틀린점이 없었다.
그래서 서칭 끝에 해결한 방법
- _config.yml 파일에
futrue: true
추가하기!
나는 이 방법을 통해서 무사히 해결 할 수 있었다..
github blog 업로드가 안 될 때
- 날짜를 하루 전날로 변경한다.
- _config.yml에
futrue: true
를 추가한다.
참고!
참고한 페이지 링크
마켓컬리 클론코딩
UMC 1주차 미션은 클론코딩이었다.
클론코딩은 유튜브 강의로 유튜브 클론코딩만 따라서 해본 적 밖에 없어서 어떻게 해야 할지 약간 막막했지만… 이틀동안 열심히 만들어봤다..!
react나 vue는 사용하지 않고 그냥 만드는 거라… 컴포넌트의 존재가 새삼 최고였다는 것을… 깨닫게 되었다…
한 파일에 만드니까 뭔가 헷갈린다고 해야 하나..? 정리가 안된 느낌..
그리고 css는… 차마 하나하나 따로 치기에는 너무 헷갈리고 힘든 미래가 보여서 scss를 사용했다. 간단히 scss 사용하는 방법은 다른 글에 작성하기로…
이틀동안 만드느라 시간이 부족해서 자바스크립트는 사용하지 않았다. 페이지 자동으로 변환되거나.. 시간 움직이기 등을 했어야 했는데.. 시간이 없는 관계로 선택과 집중을 했다.
그리고 버튼이나 링크 하나 하나 신경써서 하기에는 시간도 없고.. 복잡(?)하므로 쿨하게 패스하고 다 모양만 만들어줬다.


내가 만든 마켓컬리 클론코딩 페이지!
어려웠던 점
클론코딩을 하면서 어려운 점은.. 기존에 코드를 참고해서 하는데, 해당 코드를 바탕으로 새롭게 나만의 코드 만드는게 처음이라 애를 좀 먹었다. 어떻게 해야 할 지 감을 잡는데 조금 걸렸달까? 그래도 여러번 반복되니 이제 대략 코드들도 이해가 되고 버려도 되는 코드를 금방 파악할 수 있어서 후반부에 갈 수록 코드 작성하는 시간은 적게 걸렸다.
그런 점 말고는… 딱히…?
그저.. vue나 react를 사용하지 않으니까 정리가 안된 느낌이라 답답했다는 것?! 정도?
후반부에는 react를 사용하게 될 거니까 괜찮을 것이다.
종합 소감
클론코딩… 결코 만만하지 않은 것이었다..
TIL!!
-
object-fit
<img>
나 <video>
요소의 크기를 어떤 방식에 맞출 것인지 지정한다.
-
contain
대체 콘텐츠의 가로 세로비를 유지하면서, 요소의 콘텐츠 박스 내부에 들어가도록 크기를 맞춤 조절한다.
-
cover
대체 콘텐츠의 가로 세로비를 유지하면서, 요소 콘텐츠 박스를 가득 채운다. 가로 세러비가 일치하지 않으면 객체 일부가 잘려나간다.
-
fill
콘텐츠 박스 크기에 맞춰 대체 콘텐츠의 크기를 조절한다. 콘텐츠가 박스를 가득 채운다. 가로세로비가 일치하지 않으면 콘텐츠가 늘어난다.
object-fit - CSS: Cascading Style Sheets : MDN
-
z-index
요소를 가장 앞에 배치하고 싶다면 큰 수를 작성한다.
단! z-index를 작성할 때, 항상 position 값은 relative로 설정해줘야 z-index가 작동한다. static일 때는 적용되지 않는다.
/* 최상위 요소 */
.first {
position: relative;
z-index: 9999;
}
/* 밑에 깔리는 요소*/
.second {
position: relative;
z-index: 10;
}
z-index - CSS: Cascading Style Sheets : MDN
-
letter-spacing
글자 사이의 간격을 조절한다.
값이 커지면 간격이 커진다. 값에 음수를 넣을 수 있으나 글자가 겹칠 수 있다.
추가로 단어 사이의 간격은 word-spacing이다.
p {
letter-spacing: 10px;
}
letter-spacing - CSS: Cascading Style Sheets : MDN
내용이 많아질 수록 css를 작성하기 복잡해진다. 이때, scss를 사용하면 조금 더 손쉽게 스타일을 적용할 수 있다.
파일 만들기
일단 간단하게 예시를 들기 위해서 총 3개의 파일을 만들어준다.
파일들을 생성했다면 index.html 파일에 css를 연결해준다.
scss 파일이 아닌 css 파일이여야 한다! html은 scss 파일을 읽지 못한다.
scss를 css로 변환하기
우리는 scss 파일에 스타일을 작성해준다. 하지만 그냥 작성하고 저장하면 css 파일은 백지이다. 즉, 가만히 그냥 두면 변환은 일어나지 않는다.
우리는 scss 파일을 css 파일로 변환을 해줘야 한다. cmd창에 다음과 같은 명령어를 작성한다.
npx sass --watch 폴더명/scss파일명 폴더명/css파일명
npx sass --watch css/style.scss css/style.css
여기서 --watch
는 우리가 scss파일에 작성한 코드를 저장하면 자동으로 css 파일로 변환해줘~ 라는 명령어다.
해당 명령어를 작성하지 않으면 scss 파일을 저장하고, cmd 창에서 수동으로 변환 명령어를 계속 입력해야 한다. 매번 그러기에는 귀찮으니 다음 명령어를 꼭 같이 넣어도록 하자.
참고로 더이상 변환을 시키고 싶지 않다면, cmd 창에서 control+C를 통해 프로세스를 종료시키도록 하자.