React Aptor

2.0.0 · active · verified Sun Apr 19

React Aptor is a minimal API connector for React applications, currently at version 2.0.0. It provides a structured and opinionated way to integrate vanilla JavaScript third-party libraries, especially those that interact directly with the DOM, into React components. The library addresses common integration challenges such as finding DOM nodes, preventing excessive re-renders, and managing API lifecycles without relying on global scope or introducing unnecessary abstraction layers. Emphasizing a "zero-dependency," "tree-shakeable," and "side-effect free" design, React Aptor boasts a minimal bundle size (less than 1 kilobyte). While a strict release cadence is not specified, recent updates, including the significant v2.0.0 release, indicate active development focused on improving the build process, testing infrastructure, and project consistency. Its core differentiator is empowering developers with full control over their API definitions and their connection to React, aiming to be anti-pattern-free within the React ecosystem.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates connecting a custom 'CounterLib' third-party library to a React component using `useAptor` by defining `instantiateCounter` and `getCounterAPI` functions, then consuming the exposed API.

import React, { useRef, useEffect, useState } from 'react';
import { useAptor } from 'react-aptor';

// 1. Define the instantiate function for a dummy third-party library
// Let's imagine a simple counter library that updates a DOM element.
class CounterLib {
  private count: number = 0;
  private displayElement: HTMLElement;

  constructor(node: HTMLElement, initialCount: number = 0) {
    this.displayElement = node;
    this.count = initialCount;
    this.render();
  }

  increment = () => {
    this.count++;
    this.render();
  };

  decrement = () => {
    this.count--;
    this.render();
  };

  getCount = () => this.count;

  destroy = () => {
    this.displayElement.innerHTML = ''; // Clean up DOM
    console.log('CounterLib destroyed');
  };

  private render = () => {
    this.displayElement.innerHTML = `Current count: ${this.count}`;
  };
}

const instantiateCounter = (node: HTMLElement, initialCount: number) => {
  return new CounterLib(node, initialCount);
};

// 2. Define the get API function
const getCounterAPI = (instance: CounterLib) => ({
  increment: instance.increment,
  decrement: instance.decrement,
  getCount: instance.getCount,
});

// 3. Connect API to react by useAptor
function CounterComponent() {
  const containerRef = useRef<HTMLDivElement>(null);
  const { api: counterApi, instance: counterInstance, isReady } = useAptor(
    instantiateCounter,
    getCounterAPI,
    containerRef, // The node for the third-party lib
    [0] // params for instantiateCounter: initialCount
  );

  useEffect(() => {
    if (isReady && counterApi) {
      console.log('Counter API is ready, current count:', counterApi.getCount());
    }
  }, [isReady, counterApi]);

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc' }}>
      <h2>React Aptor Counter Example</h2>
      <div ref={containerRef} style={{ marginBottom: '10px' }}>
        {/* CounterLib will render here */}
      </div>
      {isReady && counterApi ? (
        <div>
          <button onClick={counterApi.increment} style={{ marginRight: '10px' }}>Increment</button>
          <button onClick={counterApi.decrement}>Decrement</button>
          <p>Count from React state: {counterApi.getCount()}</p>
        </div>
      ) : (
        <p>Loading Counter...</p>
      )}
    </div>
  );
}

// Example usage in an App component
const App = () => <CounterComponent />;
export default App;

view raw JSON →