---
# System prepended metadata

title: Effectful한 프론트엔드 프레임워크

---

# Effectful한 프론트엔드 프레임워크

## 컴포넌트

- `(props: P) => Effect<void, E, R | RenderScope>`
- `render(eff: Effect<void, never, RenderScope>)`에 넣어서 렌더링

## 이벤트

- 이벤트 핸들러는 이펙트를 반환할 수 있다.
- 이벤트 핸들러가 반환할 이펙트의 `R`이나 `E`가 해당 핸들러가 바인딩될 요소의 E로 전이될 수 있는가?
    - 가능하다면 이벤트 핸들러에서 `Effect<R, E, unknown>`을 반환하도록 인터페이스를 구성하더라도 `R`, `E`를 적절하게 전이시킬 수 있음
        - 근데 가능하다고 해도 이게 유저랜드 컴포넌트들이 임의의 이벤트 핸들러들에 대해 구현할 수 있을 만큼 충분히 쉬운가?
    - 불가능하다면.... 모든 이벤트 핸들러는 `Effect<never, never, unknown>`를 반환해야 함

## 에러

- 컴포넌트가 반환한 `E`를 처리
- TS는 개별 JSX 요소가 반환한 `E`를 부모 요소의 `E`로 전이시킬 수 있을 만큼 똑똑한가?
    - 가능하다면 컴포넌트를 별도 에러 핸들링 없이도 바로 JSX에서 사용할 수 있음
        - 리렌더는 어떻게?
            - ㅁ
    - 불가능하다면... `E`를 핸들링한 후에야 JSX화시킬 수 있음

## 비동기

- Effect 특성상 비동기 렌더링 자체는 걍.... await하면 됨
- 근데 그걸 원하는 게 아님
- Suspense의 구현이 가능한가?
    - 먼저 fallback을 띄우고, `children` 이펙트를 fork해서 실행한 다음, 실행이 끝나면 실행 결과를 그린다
- 리렌더는 어떻게?
    - ㅁ

```ts=
const Comp = (props) => Effect.gen(function* () {
  const [count, setCount] = yield* createSignal(0);
  const doubleCount = yield* createDerived(pipe(
    count,
    Effect.map((count) => count * 2),
  ));
  const asyncData = yield* createDerived(
    Effect.gen(function* () {
      const value = yield* doubleCount;
      const data = yield* Fetch(value);
      return data;
    }),
  );
    
  yield* render(
    Suspense({
      children: El.div({
        children: Effect.map(
          asyncData,
          (data) => `Data: ${data}`,
        ),
      }),
      fallback: El.div({ children: "Loading..." }),
    }),
  );
})
```