Document Object Model은 html 단위 하나하나를 객체로 생각하는 모델이다.
예를 들어 div라는 객체는 텍스트 노드, 자식 노드 등등 하위의 어떤 값을 가지고 있다.
이런 구조를 트리구조라 한다. 따라서 DOM은 트리구조를 갖는다.
트리구조란 부모, 자식의 포함관계를 이루는 형태를 말한다.
각 html 요소마다 상대적으로 부모 자식의 포함관계를 갖게 되는데 아래의 그림처럼 우리가 마크업 할때의 구조로 요소가 어떤 요소에 의해 포함되는지를 확인 할 수 있다.
같은 레벨에 위치한 요소는 형제관계 (siblings) 라고 표현한다.
유사배열이란 Array와 같은 구조로 이루어진 객체를 말한다.
객체이지만 배열과 같이 인덱스와 length 값을 갖고 있다.
배열과 다른점은 구조는 갖지만 자료형태가 배열이 아니기 때문에 Array 내장함수인 map, filter 등을 사용 할 수 없다는 점이 특징이다.
<body>
<script src="***.js"></script>
</body>
스크립트 파일을 body태그 끝에 붙이는 이유는 javascript에서 참조하는 DOM객체가 로드된 후에 스크립트에서 제대로 참조할 수 있도록 하기 위해서 이다.
함수 선언식
function foo() {...}
함수 표현식
let foo = function() [함수명]{...}
화살표 함수
let foo = () => {...}
Class
객체 지향 프로그래밍에서 클래스는 특정 객체를 생성하기 위해 변수와 함수를 정의하는 일종의 틀을 말한다. 객체를 정의하기 위한 상태와 함수로 구성되어 있으며, 객체 단위로 코드를 그룹화하고 쉽게 재사용하기위해 사용된다.
클래스를 구성하는것
class Cat {
// 객체 인스턴스 생성시 만들어지는 상태값 property
constructor(name) {
this.name = name;
}
// 객체에서 정의한 함수
showName() {
console.log(this.name)
}
}
let cat = new Cat('perl')
cat.showName() // 'perl' ... showName에서 실행된 console.log를 출력
console.log(cat) // Cat {name: "perl"} ... Cat 객체를 출력
class MyCat extends Cat {
constructor(name, age) {
super(name) // 상속받은 클래스의 프로퍼티에 접근하기 위함
this.age = age
}
// 부모 클래스가 가진 것과 같은 이름의 함수를 만들 수 있습니다.
// 오버라이딩
showName(){
console.log(this.name);
// super를 키워드로 사용하기
return '내 고양이 이름은 '+super.showName()+'입니다.';
}
showAge() {
console.log(this.age)
}
}
let my_cat = new MyCat('perl', 4)
my_cat.showAge() // 4
my_cat.showName() // 'perl 입니다'
1) = 는 할당
2) == 은 자료형을 비교하지 않는 비교
(ex: 0 == '0' // true)
3) === 은 자료형과 값을 둘다 비교
(ex: 0 == '0' // false)
Spread 연산자
어떤 객체 안에 있는 요소들을 객체 바깥으로 꺼내주는 역할
삼항연산자
Array 내장함수 (map, filter, concat, from)
Array.from() 사용 예제
const my_name = 'chansoo'
const my_name_array = Array.from(my_name)
console.log(my_name_array) // ['c','h','a','n','s','o','o']
const num_array = Array.from(my_name, (item, idx) => idx)
console.log(num_array) // [0,1,2,3,4,5,6]
const new_array = Array.from({length: 4}, (item, idx) => idx)
console.log(new_array) // [0, 1, 2, 3]
(요약) 렌더링 되는 연산을 최소화 하기 위해서 전체 화면을 렌더링하는것이 아니라 렌더링 전 가상돔과 비교하여 변경된 부분의 DOM만 렌더링 할 수 있도록 하기 위해 사용하는 개념이다.
(더 자세한 내용 업데이트 할것)
생성 - 수정 - 제거
- 생성단계: 처음으로 컴포넌트를 불러오는단계
- 수정: 사용자의 행동으로 데이터가 바뀌거나 부모 컴포넌트가 렌더링 될때 업데이트는 단계 (props가 바뀔때, state가 바뀔때, 부모 컴포넌트가 업데이트 되었을때 = 리렌더링 했을때, 강제 업데이트 했을 경우 = forceUpdate()를 사용했을때)
- 제거: 페이지를 이동하거나, 사용자의 행동으로 컴포넌트가 화면에서 사라지는 단계
Styled Components는 상당히 재미있었다.
우선 js파일안에서 css를 작성하여 바로 적용 시킬 수 있고 nested 방식으로 css를 작성 할 수 있는데 scss에서 스타일링하는 코드와 같아 보인다.
또 템플릿 리터럴로 작성되기 때문에 변수 사용이 가능하며
부모 컴포넌트에서 데이터를 넘기듯이 props를 넘겨 스타일을 작성할때 가변적인 코드를 만들어 줄 수 있다.
이때 props를 받아오는 코드가 조금 특이한데 arrow funcion처럼 함수 매개변수로 받아와서 사용이 가능하고 구조분해할당으로 위 코드를 아래처럼도 사용 가능하다.
보통 브라우저 기본 스타일을 리셋하기위해서 간단히 전체선택자에 margin, padding, box-sizing을 넣는데.. styled-components는 각각의 스타일 데이터 코드를 변수에 담아 컴포넌트처럼 적용한다.
전체 스타일을 위해서 기존의 방식대로 css 파일을 만들어 사용해야한다면 조금 아쉬운 상황이다.
구글링과 유튜브를 검색해보니 GlobalStyle을 만들어 적용 시킬 수 있다고 한다.
style components에서 GlobalStyle 적용하기
나는 위와같이 Global.js를 만들어 전체선택자에 적용할 코드를 작성하였다. 이때 기존 styled-components 작성법과 다른점은 createGlobalStyle이라는 키워드를 쓰며, 따로 태그의 이름을 지정하지 않는다는 것이다.
다 작성된 코드를 export하여 App.js에서 import한 후 컴포넌트만 추가해 주었더니 해결되었다.
기존에 CSS방식과 사용법이 많이 다르기때문에 조금 어색하지만 익숙해지면 훨씬 더 코드 관리가 편하고 직관적일것같다.
바닐라 자바스크립트에서 DOM을 참조할때는 getElementById같은 메서드로 DOM 객체에 접근한다. 이것은 실제 렌더링이 완료된 요소에 접근을 하는것인데!
리액트는 Virtual DOM를 사용한 렌더링 과정을 거치기 때문에 getElementById와 같이 DOM을 참조하려해도 가상 DOM에서 변경된 변경사항을 실제 DOM에 Update하기 전 상황에서는 값을 뽑아낼수가 없다.
우선 React.createRef()와 React.useRef() 둘다 가능한 방법인데
결론은 이 메서드를 활용하면 리액트 DOM에서 ref 속성의 값으로 메서드 값을 저장한 변수를 지정해 주면 DOM 참조가 가능하다고 한다.
사실 강의를 듣고도 속 시원하게 이게 왜 그런지 이해는 잘 되지 않는다.
리액트 공식문서를 찾아보면 이렇게 설명한다.
ref 어트리뷰트가 HTML 엘리먼트에 쓰였다면, 생성자에서 React.createRef()로 생성된 ref는 자신을 전달받은 DOM 엘리먼트를 current 프로퍼티의 값으로서 받습니다.
ref 속성에 값으로 this.myRef를 주었고 이 프로퍼티는 생성자에서 React.createRef()로 생성된 자신을 current로 접근 가능하게 한다고 한다.
createRef()를 쓰지 않고 DOM에 직접 접근하는 방식도 있다고 해서 알아보았는데
핵심은 참조하고자 하는 요소에 ref 속성 값으로 ref라는 인자값을 해당 컴포넌트 속성값으로 저장하는 방식이었다.
이때 ref 속성에 매개변수로 받는 ref를 찍어보았는데
자기 자신을 리턴한다.
그럼 createRef()를 통해서 이 ref에서 리턴한 자기자신을 current 키값으로 접근할수있게 해주는것이 아닐까..
우선은 사용방식을 잘 익혀서 써보도록하고 확실히 이해하는것은 나중에 또 알아보는것이 좋겠다.
단방향 데이터 흐름이란?
데이터는 위에서 아래로, 부모에서 자식으로 넘겨줘야 한다.
리액트의 라이프 사이클에 특성상 렌더링이 이루어 지는경우는 4가지 경우인데
내 state가 바뀌거나, props가 바뀌거나, 부모 컴포넌트가 리렌더링 되거나, 강제 렌더링이 되거나..
만약 자식 컴포넌트의 state가 바뀌었을때 렌더링이 된다면 자식 변경값을 부모 컴포넌트로 props로 받는다고 가정했을때 부모컴포넌트가 리렌더링 된다. 그럼 다시 자식컴포넌트가 부모컴포넌트에 의해 렌더링되면서 렌더링 무한루프에 빠지게 되기 때문에 이러한 데이터 흐름을 갖고있다고 한다.
this.setState() // 클래스 컴포넌트 에서 state를 변경할때 사용한다.
useState() // 함수형 컴포넌트 에서 state를 변경할때 사용한다.
클래스형 컴포넌트에서는 ref로 참조되고있는 요소에 이벤트를 리스닝시킬 수 있는데, DOM이 올라간 후에 이벤트를 등록 할 수 있기에 componentDidMount() 시점에 등록을 한다. 반대로 이벤트를 제거 할 때는 Unmount 시점에서 이벤트를 해제 시킨다.
함수형 컴포넌트에서는 useEffect() 함수를 사용하는데 이 함수는
componentDidMount() componentDidUpdate() componenetWillUnmount() 를 합쳐 놓은 것이라고 생각하면 쉽다.
Multi Page Application
여러개의 html 페이지를 갖고 있는 어플리캐이션으로 정적 파일을 페이지가 이동할때마다 받아와야 하며 상태값을 유지하기 어렵다는 단점이 있다.
Single Page Application
하나의 html 페이지를 갖고 있는 어플리캐이션으로 페이지를 이동 할때 마다 정적 파일을 받아오는것이 아니라 변화가 생긴 부분만 불러와 효율적으로 사용 할 수 있고 페이지를 이동 할 때마다 페이지를 새로 불러오는것이 아니기 때문에 상태 유지에 효과적이다.
단, 처음 페이지를 불러올때 모든 컴포넌트를 받아와야하기 때문에 첫 로딩시에 속도가 느려 질 수 있다는 단점도 있다.
react-router-dom 라이브러리 활용
리액트 라우터를 사용하기 위해서는 react-router-dom 라이브러리를 활용하는데 내 프로젝트에서 리액트 라우터 사용환경을 만들기 위해서는 필요한 컴포넌트 부분을 감싸주거나 아니면 루트 컴포넌트를 BrowerRouter로 감싸 라우트를 사용할 환경을 만들어 줄수 있다.
각 컴포넌트를 url 주소에 맞게 라우팅 하기
Route를 import하여 path 속성을 사용해 해당 url에 맞게 보여질 컴포넌트를 자식요소로 배치할 수 있다. 이때 path 속성은 중첩으로 사용이되어 '/cat' 로 이동했을때 url은 '/' 을 포함하기 때문에 Home 컴포넌트와 Cat 컴포넌트를 둘다 보여주게 되는데 이를 피하기 위해서는 exact 속성으로 정확히 path와 일치할때 컴포넌트를 라우팅하게 할 수 있다.
<Route path="/cat/:cat_name" exact component={Cat}>
페이지 이동하기
페이지 이동 시 history 객체 사용 하기
history 객체를 사용하는 방법
첫번째 라우팅 시에 자식 컴포넌트를 그대로 props으로 사용하여 컴포넌트 객체에서 찾아서 쓰는 방법이 있다.
두번째 useHistory를 사용하여 히스토리 객체만 따로 꺼내어 사용하는 방법이다. 이때는 부모 컴포넌트에서 라우팅을 할때 props로 자식컴포넌트를 넘길 필요없이 Hook을 사용해 history 객체에 접근할 수가 있다.
데이터 상태 전역관리
과정
1) 리덕스 Store를 Component에 연결
2) Component에서 상태 변화가 필요할 때 Action을 부른다.
3) Reducer를 통해서 새로운 상태 값을 만들고,
4) 새 상태값을 Store에 저장한다.
5) Component는 새로운 상태값을 받아온다 (props를 통해 받아오니까 다시 렌더링 발생)
미들웨어?
서버에서 데이터를 가져와야 할때 (비동기 통신) 등의 중간다리 라이브러리
기능별로 만드는 ducks 구조 [github]
import 해야할것
import styled, { keyframes } from 'styled-components'
사용 방법
const boxAnimation = keyframes`
0% {
border-radius: 0;
}
50% {
border-radius: 50%;
top: 400px;
}
100% {
border-radius: 0;
top: 20px;
}
`
const Box = styled.div`
width: 100px;
height: 100px;
background: lightgreen;
border-radius: 0;
position: absolute;
top: 20px;
left: 20px;
animation: ${boxAnimation} 1s infinite ease-out alternate;
Firebase [링크]
서버리스 서비스
서버가 해야하는 일들을 미리 만들어 놓은 서비스
BaaS
Backend as a Service의 약자로 데이터베이스, 소셜 서비스 연동, 파일시스템 등을 API 형태로 제공해주는 서비스
Firebase에 포함되어 있는 서비스 중 하나로 유연하고 확장 가능한 NoSQL 클라우드 데이터서비스 입니다.
$ yarn add firebase
사용하고자 하는 서비스 액세스 하기
웹 버전 선택 시 프로젝트에 설치되어있는 firbase 패키지 버전과 맞춰주면 된다.
![](https://velog.velcdn.com/images%2Fcslim0527%2Fpost%2Fe98708e5-555c-43b3-a31b-70ec91922361%2Fimage.png)
Firebase SDK 프로젝트에 작성하기
![](https://velog.velcdn.com/images%2Fcslim0527%2Fpost%2Fbae95113-dd08-4ff2-9ed5-d1ff5504189d%2Fimage.png)
![](https://velog.velcdn.com/images%2Fcslim0527%2Fpost%2F8def589e-39bf-4968-90c7-231ffe265578%2Fimage.png)
import 해야할 패키지
import { collection, getDoc, getDocs, addDoc, updateDoc, deleteDoc } from 'firebase/firestore'
우선 MySQL에서는 DB -> 테이블 -> 필드 라는 관계를 갖고 있는데 FireStore에서는
Collection -> Docs -> Field 이런 구조로 이뤄져있는거로 보인다.
(그냥 내 머리에서 나온 추측이므로, 사용해보면서 이 개념이 틀리면 정보 수정할것!!!!!!!!!!!!!!!!!)
Docs가 테이블의 각 Row로 봐야하나..? %@#! 똑같은 개념이 아니라 구조가 다를수 있겠지..?
첫번째로 나의 Docs에 접근하기 위해서는 먼저
Collection 함수에 getFirestore()로 만든 객체와 접근할 Document 이름을 넘긴 후,
getDocs() 함수를 통해 정보를 받아 올 수 있다.
이때 getDocs()는 Firestore API를 사용하여 비동기 통신을 하는것이기 때문에 async, await를 사용하여 데이터를 온전히 받아올 수 있는것 같다.
const query = await getDocs(collection(db, 'bucket'))
불러온 정보들의 필드값을 조회하기 위해서 query 변수에 받아온 정보들을 하나씩 살펴보려면
forEach() 메서드를 사용해서 볼 수 있는데 이때 forEach()는 자바스크립트 배열 내장 함수와 다른것이기 때문에 헷갈릴수 있으니 꼭 유의하자.
getDocs().forEach() !== Array.forEach()
forEach()로 객체에 접근했을때 해당 매개변수를 data() 메서드로 불러들이면 필드값을 조회할 수있다.
// collection 정보 추가하기
addDoc(collection(db, 'bucket'), {
text: 'firestore',
completed: false
})
const docRef = doc(db, 'bucket', 'H9xebPRbY8612dwPFl7w')
updateDoc(docRef, {completed: true})
const docRef = doc(db, 'bucket', 'H9xebPRbY8612dwPFl7w')
deleteDoc(docRef)
yarn add redux-thunk
redux-thunk는 특정 액션이 발생하기 전에 조건을 주거나 사전 처리 로직을 실행 할 수 있도록 액션 함수를 작성 할 수 있게 도와준다.
########## 미들웨어 실습한것 정리해서 올릴것 (메모 작성일 11/18) #############