aquedux

react components directly manipulated by streams

Usage no npm install needed!

<script type="module">
  import aquedux from 'https://cdn.skypack.dev/aquedux';
</script>

README

Aquedux

react components directly manipulated by streams

Why?

Sometimes you want to manipulate your object styles / properties directly to prevent re-rendering (for example an effect while scrolling). This library allows you to pass an rxjs like observable to your component, and create a subscrpition, to the value change. This approach is very similar react-native Animated api.

Instalation

npm i -S aquedux

Usage

Try example on this code sandbox

import React, { useMemo, useCallback } from 'react';
import { Aquedux } from "aquedux";
import { BehaviorSubject } from "rxjs";
import { map } from "rxjs/operators";

const toRgb = (v: number) => {
  const hex = v.toString(16);
  return `#${'0'.repeat(6 - hex.length)}${hex}`
};

export const App = () => {
  const $color = useMemo(() => new BehaviorSubject(0xFFFFFF), []);
  const $coordinates = useMemo(() => new BehaviorSubject({ x: 0, y: 0 }), []);
  const onMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
    const red = Math.floor(e.pageX / window.innerWidth * 255);
    const green = Math.floor(e.pageY / window.innerHeight * 255);
    const blue = Math.floor((window.innerWidth - e.pageX) / window.innerWidth * 255);
    // write new value to the subject
    $color.next(red << 16 | green << 8 | blue);
    $coordinates.next({ x: e.pageX, y: e.pageY });
  }, [$color, $coordinates]);

  // use Aquedux component, to accept observable value.
  return <Aquedux.div
    onMouseMove={onMouseMove}
    style={{
      width: "100%",
      height: "100%",
      display: "flex",
      justifyContent: "space-around",
      alignItems: "center",
      // assign observable to any style, and that's it :)
      backgroundColor: $color.pipe(map(toRgb))
    }}
  >
    <Aquedux.span
      style={{
        color: "black",
        fontSize: 200,
        fontFamily: "Arial",
        fontWeight: "bold",
        userSelect: "none",
      }}
    >
      {/* You can also set directly children to html components */}
      {$coordinates.pipe(map(({ x, y }) => `${x}:${y}`))}
    </Aquedux.span>
  </Aquedux.div>
};

Enhancing custom components

To create a custom component you can import createAxComponent utility and wrap your component with it. By default it will shallowly enhance your properties to accept observable values. If you'd like some property to be deeply enhanced (common scenario style), you pass second param with specifying those.

import { createAxComponent } from 'aquedux';

const div = createAxComponent(
  Div,
  { style: true }
);