Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/danpacho/vanilla-todo
직접 만든 ⚡️vanilla reactive component⚡️로 todo앱을 제작해봅니다!
https://github.com/danpacho/vanilla-todo
reactive-programming vanilla-components vanilla-javascript
Last synced: 1 day ago
JSON representation
직접 만든 ⚡️vanilla reactive component⚡️로 todo앱을 제작해봅니다!
- Host: GitHub
- URL: https://github.com/danpacho/vanilla-todo
- Owner: danpacho
- Created: 2022-11-11T05:53:29.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2022-11-13T06:34:18.000Z (about 2 years ago)
- Last Synced: 2024-11-13T01:38:02.004Z (1 day ago)
- Topics: reactive-programming, vanilla-components, vanilla-javascript
- Language: TypeScript
- Homepage:
- Size: 2.42 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# CRUD Todo List / 7일
## 중점적인 고민 사항 🧐
> component 디자인 개선과 **reactiveness** 추가
1. 정적인 `html` 템플릿과 **reactiveness**와 rerendering 로직을 추가해봅시다!
2. 절차적 프로그래밍 함수형 프로그래밍으로 개선해봅시다!
3. `js`를 `ts`로 변경하여 구조적 안정성을 추가해봅시다! (개인 진행)## Reactiveness 해결 방법 🔥
> 반응형 상태 시스템 구축
### 1. `signal`: 상태를 담고 있는 전기 신호
> 라디오 `캐스터👨🚀`가 **`방송🎙️`**(**`전기 신호`**)을 한다고 생각을 해봅시다.
**선언형** 상태, signal
```ts
const [count, setCount, resetCount, prevCount] = signal(0)
```**`signal` 사용하기** / 조회와 업데이트
1. `count` - signal의 **현재 상태를 반환하는** `getter`입니다.
2. `setCount` - signal의 **상태를 업데이트하는** `setter`입니다.
3. `resetCount` - **signal의 초기값으로 초기화 하는** `setter`입니다.
4. `prevCount` - **signal의 바로 직전 상태를 반환하는** `getter`입니다.```ts
count()
//🟢 0setCount(1)
//🟢 1setCount((c) => c + 99)
//🟢 100resetCount()
//🟢 0prevCount()
//🟢 100
```### 2. `track`: 사용하는 `signal`을 관찰하고 변화되면 저장된 함수를 실행
> 캐스터의 **`방송🎙️`**(**`전기 신호`**)을 송출하는 **`방송국🛰️`** 으로 생각해봅시다.
>
> 방송국은 캐스터가 **`방송🎙️`**(**`전기 신호`**)을 시작하기 전까지 **`대기`**(**`관찰`**) 하다가, 방송이 시작되면 **`송출`**(**`저장된 함수를 실행`**) 하는 것과 같습니다.```ts
const [count, setCount, resetCount, prevCount] = signal(0)setCount((c) => c + 1)
setCount((c) => c + 1)
setCount((c) => c + 1)track(() => {
// ✅ count를 관찰합니다
console.log(count() % 2 === 0 ? "짝수" : "홀수")//🟢 console => "짝수"
//🟢 console => "홀수"
//🟢 console => "짝수"
//🟢 console => "홀수"
})
```### 3. reactive `component`: 사용되는 `signal`을 관찰하고 변화되면 **rerendering**
```ts
const Counter = () => {
const [count, setCount] = signal(0)const plus = () = setCount(c => c + 1)
const minus = () = setCount(c => c - 1)return $component(
() => html`
🔺
${count()}
🔻
`
)
.addEvent(() => ({
targetId: "plus",
type: "click",
handler: plus,
}))
.addEvent(() => ({
targetId: "minus",
type: "click",
handler: minus,
}))
}Counter().render()
```### 4. static `component`: 상태 변경이 없는 컴포넌트를 `DOM` tree에 mount할 때 사용
> 레이아웃과 같은 정적인 틀을 컴포넌트화 할때 사용합니다.
reactive component로 선언하는 경우, **rerendering** 시 `DOM` tree에 mount되기 전에 특정 `id`에 접근하려고 할때 불가능한 문제가 발생합니다.
✅ 특정 `id`에 reactive component mount시키기
```ts
const App = () =>
component(
() => html`
`
)App().render()
// App은 "#app"에 mount 되었습니다.//✅ 성공적으로 #todo-list-head에 mount됩니다.
SomeReactiveComponent.render("todo-list-head")
```🚫 특정 `id`에 rerendering시 접근 불가
```ts
const App = () =>
$component(
() => html`
`
)App().render()
// 🚫 App이 rerender 될 때, mount되지 않았기에 SomeReactiveComponent는 "todo-list-head"에 mount되지 않습니다.
SomeReactiveComponent.render("todo-list-head")
```### 5. static `template`: `html` template로 반복되는 렌더링 로직 추출
```ts
const Button = ({ text, emoji }: ButtonProps) => {
return html`
${text}
${emoji ? `${emoji}` : ""}
`
}Button({ text: "이건 버튼", emoji: "✅" })
// Button은 그저 템플릿일뿐, component(() => html`...`)에서 사용 전에는 mount되지 않습니다.
```[tagged-template-literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)문법을 이용해 `html`을 만들어 `lit-html`확장을 사용하여 개발 편의성(DX)을 높여보았습니다!
- `lit-html` - html``로 내부의 요소를 하이라이팅 해줌
![lit-html vscode 확장](/assets/extension.png)
- 해당기능을 함께 사용하지 않을 때 🤬
![lit-html vscode 확장](/assets/without.png)
- 해당기능을 함께 사용할 때 🤗
![lit-html vscode 확장](/assets/with.png)## 구현사항 ✅
1. 투두 추가(Create)
2. 투두 변경사항 UI 즉시 반영(Read)
3. 투두 삭제(Delete)
4. 투두 수정(Update)
5. `web storage api`를 활용한 브라우저 데이터 유지
6. `media query`를 사용한 mobile 중심 반응형 디자인
**mobile UI** → **desktop UI** 로 제작## 구현결과 🎉
![심연의 투두리스트!](./assets/demo.gif)
## 좋았던 점 ✅
1. `solidJs`의 reactive 방법론을 적용하여 성공적으로 statefull한 컴포넌트를 제작할 수 있었습니다.
2. 자동적으로 의존성(dependncy)을 추적하며 렌더링 하기에 `react`에서 자주 등장하는 human error가 적어졌습니다.
부수효과를 다룰 때 사용하는 `react`의 `useEffect`
```tsx
const Counter = () => {
const [count, setCount] = React.useState(0)React.useEffect(() => {
// count값의 변경을 감지하기 위해 명시적으로 dependency를 작성해줘야 함
}, [count])//...
}
````track` 함수로 자동으로 의존성 추적
```ts
const Counter = () => {
const [count, setCount] = signal(0)track(() => {
count()
// count를 tract callback에서 호출하면 자동으로 의존성이 추적됨
})//...
}
```## 개선해보면 좋은점 🔸
1. `signal` 호출에 **memoization** 함수가 따로 없기에, 같은 내용을 연산할 때 불필요한 렌더링이 발생합니다.
2. `event`를 다량으로 부착시 가독성이 좋지 않습니다.
`jsx`를 사용하지 않기에 발생하는 문제입니다... `inline event` 부착 등도 고려 했으나, 모든 `evnet handler`를 전역적으로 선언해야 하기에 코드 품질면에서 좋지 않습니다.🥲3. component 생성시에 parent `div`(일명 fragment)가 존재하고 원하는 위치(특정 `id`)에 렌더링하기가 까다롭습니다.