>  기사  >  웹 프론트엔드  >  Rimmel.js와 함께 이벤트 매퍼 사용: 간단한 소개

Rimmel.js와 함께 이벤트 매퍼 사용: 간단한 소개

Patricia Arquette
Patricia Arquette원래의
2024-10-16 18:26:15157검색

If you want to improve the overall quality of your code, you may want to keep your data models neatly decoupled from the underlying views.

Functional-Reactive frameworks or UI libraries like Rimmel.js, which have full support for Observables, enable you to define your models as Observable streams (e.g.: simple data in, data out streams) in addition to a little-known design pattern which is the event adapter.

Using Event Mappers with Rimmel.js: a simple introduction

Event adapters help you map any source events (E.G.: the DOM's MouseEvent, PointerEvent, KeyboardEvent, etc) to the format actually used by your data models, so they'll be freed from this conversion task and be ultimately decoupled from the UI.

Rimmel makes it simple to connect such a stream to the DOM:

import { rml } from 'rimmel';

const component = () => {
  const total = new Subject().pipe(
    map(x => doSomethingWith(x)),
  );

  return rml`
    <button onclick="${stream}">click me</button>
    <div id="display">${stream}</div>
  `;
}

The binding is trivial: Rimmel connects click events coming from the button directly into your observable stream, which will receive instances of PointerEvent every time the button is clicked.

So far so good. What if your stream needs to take data from multiple sources, and behave differently depending on each?
Let's create a simple counter with an increment and a decrement button, each adding or subtracting one from it.

import { scan } from 'rxjs';
import { rml } from 'rimmel';

const component = () => {
  const total = new BehaviorSubject(0).pipe(
    scan((old, new) => old+new, 0),
  );

  return rml`
    <button onclick="${() => total.next(1)}">inc</button>
    <button onclick="${() => total.next(-1)}">dec</button>

    <div>${total}</div>
  `;
}

This works, but the template part is including some logic, which is an anti-pattern. Ideally we should strive to have logic-less templates to maximise testability overall.

So, with Rimmel 1.2 you have a new feature, Event Mappers, which help exactly with that. They help you map DOM events into what your model needs, so you can keep logic perfectly separate from the template. Here's how it works.

import { map, scan } from 'rxjs';
import { rml, reversePipe } from 'rimmel';

const Inc = reversePipe(map(() => 1));
const Dec = reversePipe(map(() => -1));
const component = () => {
  const total = new BehaviorSubject(0).pipe(
    scan((old, new) => old+new, 0),
  );

  return rml`
    <button onclick="${Inc(total)}">inc</button>
    <button onclick="${Dec(total)}">dec</button>

    <div>${total}</div>
  `;
};

reversePipe is the innovative addition here: a pipeline creation tool that works opposite to the pipe() function in RxJS. Whilst the latter applies transformations to the output of a stream, reversePipe() applies them at the input.
This way you're sure your main stream Subject/BehaviorSubject/Observer/EventListener always get data in the formats you want and you keep your adapter as a separate concern.

You can use any RxJS operator in your reverse pipelines. Do you only want to filter out certain events, like when the user hits Enter, rather than any other key? Just use the filter operator:

import { Subject, filter, map } from 'rxjs';
import { rml, inputPipe } from 'rimmel';

const UpperOnEnter = inputPipe(
  filter((e: Event) => e.key == 'Enter'),
  map((e: Event) => e.target.value.toUpperCase()),
);

const Component = () => {
  const state = new Subject();

  return rml`
    Type some text and hit Enter<br>
    <input onkeydown="${UpperOnEnter(state)}">
    <div>${state}</div>
  `;
};

With regards to unit testing this is a tiny but useful addition that will make tests simpler and more efficient.

Check out event mappers in action on this Stackblitz

위 내용은 Rimmel.js와 함께 이벤트 매퍼 사용: 간단한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.