CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-rax

A universal React-compatible render engine for building applications across multiple platforms

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

hooks.mddocs/

Hooks

Complete React hooks implementation for state management and side effects in functional components. All hooks are compatible with React hooks and follow the same rules and behavior patterns.

Capabilities

State Hook

Manages local state in functional components. Returns current state value and setter function.

/**
 * Manages local state in functional components
 * @param initialState - Initial state value or function returning initial state
 * @returns Array containing [currentState, setStateFunction]
 */
function useState(initialState);

Usage Examples:

import { createElement, useState } from 'rax';

function Counter() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  // With function initializer (for expensive computations)
  const [expensiveValue, setExpensiveValue] = useState(() => {
    return computeExpensiveValue();
  });

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(prevCount => prevCount - 1);

  return createElement('div', null,
    createElement('p', null, `Count: ${count}`),
    createElement('input', {
      value: name,
      onChange: (e) => setName(e.target.value),
      placeholder: 'Enter name'
    }),
    createElement('button', { onClick: increment }, '+'),
    createElement('button', { onClick: decrement }, '-')
  );
}

Effect Hook

Performs side effects in functional components. Equivalent to componentDidMount, componentDidUpdate, and componentWillUnmount combined.

/**
 * Performs side effects in functional components (deferred execution)
 * @param effect - Effect function, can return cleanup function
 * @param inputs - Optional dependency array for effect optimization
 */
function useEffect(effect, inputs);

Usage Examples:

import { createElement, useState, useEffect } from 'rax';

function DataFetcher({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  // Effect with cleanup
  useEffect(() => {
    let cancelled = false;
    
    async function fetchUser() {
      try {
        const response = await fetch(`/api/users/${userId}`);
        const userData = await response.json();
        if (!cancelled) {
          setUser(userData);
          setLoading(false);
        }
      } catch (error) {
        if (!cancelled) {
          console.error('Failed to fetch user:', error);
          setLoading(false);
        }
      }
    }

    fetchUser();

    // Cleanup function
    return () => {
      cancelled = true;
    };
  }, [userId]); // Re-run when userId changes

  // Effect without dependencies (runs after every render)
  useEffect(() => {
    document.title = user ? `User: ${user.name}` : 'Loading...';
  });

  // Effect with empty dependencies (runs once on mount)
  useEffect(() => {
    console.log('Component mounted');
    return () => console.log('Component unmounting');
  }, []);

  if (loading) {
    return createElement('div', null, 'Loading user...');
  }

  return createElement('div', null,
    createElement('h1', null, user.name),
    createElement('p', null, user.email)
  );
}

Layout Effect Hook

Synchronous version of useEffect that fires before the browser paints. Use for DOM measurements and synchronous DOM mutations.

/**
 * Synchronous version of useEffect that fires before browser paint
 * @param effect - Effect function, can return cleanup function
 * @param inputs - Optional dependency array for effect optimization
 */
function useLayoutEffect(effect, inputs);

Context Hook

Consumes context values from the nearest Provider component.

/**
 * Consumes context value from nearest Provider
 * @param context - Context object created by createContext
 * @returns Current context value
 */
function useContext(context);

Usage Examples:

import { createElement, createContext, useContext, useState } from 'rax';

// Create context
const ThemeContext = createContext('light');

function App() {
  const [theme, setTheme] = useState('light');

  return createElement(ThemeContext.Provider, { value: theme },
    createElement('div', null,
      createElement(ThemeToggle, { onToggle: () => setTheme(theme === 'light' ? 'dark' : 'light') }),
      createElement(ThemedButton)
    )
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  
  return createElement('button', {
    style: {
      backgroundColor: theme === 'light' ? '#fff' : '#333',
      color: theme === 'light' ? '#333' : '#fff'
    }
  }, `I'm ${theme} themed!`);
}

Ref Hook

Creates a mutable ref object that persists across renders.

/**
 * Creates a mutable ref object that persists across renders
 * @param initialValue - Initial value for the ref
 * @returns RefObject with current property
 */
function useRef(initialValue);

Usage Examples:

import { createElement, useRef, useEffect } from 'rax';

function FocusInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    // Focus input on mount
    if (inputRef.current) {
      inputRef.current.focus();
    }
  }, []);

  const focusInput = () => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  };

  return createElement('div', null,
    createElement('input', { ref: inputRef, type: 'text' }),
    createElement('button', { onClick: focusInput }, 'Focus Input')
  );
}

Callback Hook

Memoizes callback functions to prevent unnecessary re-renders of child components.

/**
 * Memoizes callback functions based on dependencies
 * @param callback - Function to memoize
 * @param inputs - Dependency array for memoization
 * @returns Memoized callback function
 */
function useCallback(callback, inputs);

Memo Hook

Memoizes computed values to avoid expensive calculations on every render.

/**
 * Memoizes computed values based on dependencies
 * @param create - Function that returns the value to memoize
 * @param inputs - Dependency array for memoization
 * @returns Memoized value
 */
function useMemo(create, inputs);

Usage Examples:

import { createElement, useState, useCallback, useMemo } from 'rax';

function ExpensiveCalculator({ items }) {
  const [filter, setFilter] = useState('');

  // Memoize expensive calculation
  const expensiveValue = useMemo(() => {
    console.log('Calculating expensive value...');
    return items.reduce((sum, item) => sum + item.value, 0);
  }, [items]);

  // Memoize callback to prevent child re-renders
  const handleFilterChange = useCallback((e) => {
    setFilter(e.target.value);
  }, []);

  const filteredItems = useMemo(() => {
    return items.filter(item => 
      item.name.toLowerCase().includes(filter.toLowerCase())
    );
  }, [items, filter]);

  return createElement('div', null,
    createElement('input', {
      value: filter,
      onChange: handleFilterChange,
      placeholder: 'Filter items...'
    }),
    createElement('p', null, `Total value: ${expensiveValue}`),
    createElement('p', null, `Filtered items: ${filteredItems.length}`)
  );
}

Reducer Hook

Manages complex state logic with a reducer function, similar to Redux.

/**
 * Manages state with a reducer function
 * @param reducer - Reducer function (state, action) => newState
 * @param initialArg - Initial state or argument for init function
 * @param init - Optional function to compute initial state
 * @returns Array containing [currentState, dispatchFunction]
 */
function useReducer(reducer, initialArg, init);

Usage Examples:

import { createElement, useReducer } from 'rax';

// Reducer function
function counterReducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return createElement('div', null,
    createElement('p', null, `Count: ${state.count}`),
    createElement('button', {
      onClick: () => dispatch({ type: 'increment' })
    }, '+'),
    createElement('button', {
      onClick: () => dispatch({ type: 'decrement' })
    }, '-'),
    createElement('button', {
      onClick: () => dispatch({ type: 'reset' })
    }, 'Reset')
  );
}

Imperative Handle Hook

Customizes the instance value exposed by a ref when using forwardRef.

/**
 * Customizes the instance value exposed by a ref
 * @param ref - Ref object to customize
 * @param create - Function that returns the instance value
 * @param inputs - Optional dependency array
 */
function useImperativeHandle(ref, create, inputs);

Usage Examples:

import { createElement, forwardRef, useImperativeHandle, useRef } from 'rax';

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus() {
      inputRef.current.focus();
    },
    scrollIntoView() {
      inputRef.current.scrollIntoView();
    },
    getValue() {
      return inputRef.current.value;
    }
  }), []);

  return createElement('input', { ref: inputRef, ...props });
});

function App() {
  const fancyInputRef = useRef();

  const handleFocus = () => {
    fancyInputRef.current.focus();
  };

  const handleGetValue = () => {
    alert(fancyInputRef.current.getValue());
  };

  return createElement('div', null,
    createElement(FancyInput, { ref: fancyInputRef }),
    createElement('button', { onClick: handleFocus }, 'Focus'),
    createElement('button', { onClick: handleGetValue }, 'Get Value')
  );
}

Hook Rules

All Rax hooks follow the same rules as React hooks:

  1. Only call hooks at the top level - Don't call hooks inside loops, conditions, or nested functions
  2. Only call hooks from Rax functions - Call hooks from functional components or custom hooks
  3. Hooks must be called in the same order - Don't call hooks conditionally

Types

// State hook types
type StateUpdater<S> = (prevState: S) => S;
type SetStateAction<S> = S | StateUpdater<S>;
type StateSetter<S> = (value: SetStateAction<S>) => void;

// Effect hook types
type EffectCallback = () => (void | (() => void));
type DependencyList = ReadonlyArray<any>;

// Reducer hook types
type Reducer<S, A> = (prevState: S, action: A) => S;
type ReducerState<R> = R extends Reducer<infer S, any> ? S : never;
type ReducerAction<R> = R extends Reducer<any, infer A> ? A : never;
type Dispatch<A> = (value: A) => void;

// Ref hook types
interface MutableRefObject<T> {
  current: T;
}

// Callback and memo hook types
type CallbackFunction = (...args: any[]) => any;
type MemoFactory<T> = () => T;

// Context hook types
interface Context<T> {
  Provider: ComponentType<{ value: T; children?: any }>;
  Consumer: ComponentType<{ children: (value: T) => any }>;
  _contextID: string;
  _defaultValue: T;
}

Install with Tessl CLI

npx tessl i tessl/npm-rax

docs

components.md

context.md

element-creation.md

hooks.md

index.md

react-compatibility.md

rendering.md

tile.json