React 개발만 근 2달을 하다가 다시 Vanilla JavaScript로 코드를 짜려니 다시 머리가 백지가 된 기분이다.🤯
최근 여러번의 미션을 진행하면서 겪은 실수들을 문서화 하지 않았던 점을 뼈저리게 후회했기 때문에 지금부터는 사소한 시행착오도 기록을 해보려고 한다 ✍🏻
리액트로 최근 몇 달을 개발했는데 JavaScript로 리액트의 흐름을 만들려니 또 백지가 된다... 내가 리액트의 Life-cycle에 대해 진득히 공부해 본 적이 있었던가...?🤦🏻♀️
제로초님의 강의에 따르면 Class에서의 리액트 life cycle은 다음과 같이 진행된다.
- 기본 흐름:
constructor
➡️render
➡️ref
➡️componentDidMount
- setState / props가 바뀔때: 기본 흐름 ➡️
shouldComponentUpdate
➡️render
➡️componentDidUpdate
- 상위 컴포넌트가 하위 컴포넌트를 없앴을 때: 기본 흐름 ➡️
componentWillUnmount
➡️소멸
이러한 흐름을 참고해서 만들어본 구조는 다음과 같다:
class Component {
constructor(){
this.setState();
}
setState(){
this.render();
}
render(){
this.didMount():
}
didMount(){
this.setState();
}
}
위 클래스는 아래와 같이 진행된다.
new
인스턴스 생성 ->setState()
->render()
->didMount()
->setState()
->render()
...필요시 반복...
didMount()
, setState()
, render()
가 무한반복 되는 현상을 방지하려면 아래와 같이 didMount()
메서드 안에서 선택적으로 setState()
가 실행되어야 하는 조건을 만들어야 한다.
async didMount() {
if (this.state.movieList) return; 📌 //이렇게!
const movieList = await fetchData('recommended-movies');
this.setState({ movieList : movieList });
}
const $app = document.querySelector("#app");
const $test = document.createElement("div");
$test.innerHTML = `<h2>Hello World</h2>`;
위 코드처럼 $app
이라는 DOM요소에 새로운 DOM요소를 자식으로 추가하기 위해 아래와 같이innerHTML
을 사용하고자 했다.
$app.innerHTML = $test; ❌
그러자 이런 화면이 떴다...
DOM은 OBJECT다! 그리고 innerHTML
은 TEXT를 다루기 때문에 string을 받는다!!
화면을 update 할 때에는 innerHTML을 쓰지 않는다!
template literal로 string을 만들어서 한꺼번에 추가하면 요소를 하나씩 개별적으로 다루기가 어렵기 때문.
반면 append()
는 DOM을 하나의 LIST로 쓴다.
$app.append($test); ⭕️
💡 DOM을 추가할 수 있는 2가지 방법:
append()
:
- dom에 dom을 붙임
- event를 걸어서 dom을 추가할 때 적절
insertAdjacentHTML()
:
- dom에 text를 붙임. text이기 때문에 dom에 붙기 '전'까지 "event를 걸 수가 없다"!
- render에서 insertAdjacentHTML()를 해주고, didMount에서 이벤트를 걸어야하는 이유.
script에 type을 생략하면 그냥 JavaScript가 된다.
만약 type="module"
이라고 명시해주지 않으면 Cannot use import statement outside a module라는 에러가 난다.
ES6 harmony module을 쓰려면 아래와 같이 type을 선언해줘야함.
<script type="module" src="./index.js"></script>
public
에는 무엇을 넣어야 하는 걸까? 그럼 src
에는?
도통 기준이 확실하게 잡히지를 않아서 나름의 기준을 세워보았다.
public
폴더의 역할은 static한 파일들을 모으는 곳.
static하다는 의미는 단순히 '정적'이라는 뜻만 있는 것이 아니라 entry point로써의 역할을 수행하는 것들을 의미함.
이미지나 <script>
태그에 src로 연결된 index.js 파일처럼 브라우저에 첫 화면을 HTML로 그려줄 때에 필요한 부분들로,
HTML에 original하게 존재하는 것들이라고 생각하면 좋음.
index.html에 <script type="module" src="./index.js"></script>
로 지정된 index.js는 public
디렉토리 하위에 있지만,
index.js를 통해 import 되는 App.js 파일은 src
디렉토리 하위에 있는 것을 알 수 있다.
아래와 같이 constructor()
함수 내부에 멤버 변수(ex.this.$target
)를 선언하면,
해당 클래스로 생성되는 모든 인스턴스가 멤버변수를 사용할 수 있게된다. 상속!
반면, var
, let
, const
로 선언하는 변수는 상속되지 않는다. 로컬로만 사용가능.
class App {
constructor({ $target }) {
this.$target = $target; //멤버변수는 Class에서만 쓰인다.
this.setState();
}
setState(){
this.render();
}
render () {
//인자를 전달할 때 키값을 고정해서 변수이름을 유지한다.
new MainPage({ $target: this.$target })
}
}
render()
함수 내부에서도 멤버변수로 접근해서 key-value로 저장한 객체를 인자로 전달한다.
이때 $target
이라는 key로 전달되는 value는 클래스마다 재할당 해줄 수 있기 때문에 재사용성이 올라간다.
https://www.zerocho.com/category/React/post/579b5ec26958781500ed9955
잘 보고갑니다~