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

context.mddocs/

Context API

React-compatible context system for managing and sharing state across component trees without prop drilling. Enables efficient data flow from parent components to deeply nested children.

Capabilities

Create Context

Creates a context object containing Provider and Consumer components for sharing data across component trees.

/**
 * Creates a context object for sharing data across component trees
 * @param defaultValue - Default value used when no Provider is found in tree
 * @returns Context object with Provider, Consumer, and internal properties
 */
function createContext(defaultValue);

The returned context object has the following structure:

interface ContextObject<T> {
  /**
   * Provider component that supplies context value to child components
   */
  Provider: ComponentClass<ProviderProps<T>>;
  
  /**
   * Consumer component that receives context value via render prop
   */
  Consumer: ComponentClass<ConsumerProps<T>>;
  
  /**
   * Internal context identifier (used by Rax internally)
   */
  _contextID: string;
  
  /**
   * Default value for the context (used by Rax internally)
   */
  _defaultValue: T;
  
  /**
   * Internal method for finding nearest provider (used by Rax internally)
   */
  __getNearestParentProvider: Function;
}

interface ProviderProps<T> {
  value: T;
  children?: any;
}

interface ConsumerProps<T> {
  children: (value: T) => any;
}

Usage Examples:

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

// Create context with default value
const ThemeContext = createContext('light');
const UserContext = createContext(null);

// Theme Provider Component
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
    setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
  };

  const contextValue = {
    theme,
    toggleTheme
  };

  return createElement(ThemeContext.Provider, { value: contextValue }, children);
}

// User Provider Component  
function UserProvider({ children }) {
  const [user, setUser] = useState({ name: 'John Doe', id: 1 });

  return createElement(UserContext.Provider, { value: { user, setUser } }, children);
}

// App with multiple providers
function App() {
  return createElement(ThemeProvider, null,
    createElement(UserProvider, null,
      createElement(Dashboard)
    )
  );
}

Provider Component

The Provider component supplies the context value to all descendant components. Components that consume the context will re-render when the Provider's value changes.

Provider Usage Examples:

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

const AppContext = createContext();

function AppProvider({ children }) {
  const [user, setUser] = useState(null);
  const [theme, setTheme] = useState('light');
  const [notifications, setNotifications] = useState([]);

  // Context value object
  const contextValue = {
    user,
    setUser,
    theme,
    setTheme,
    notifications,
    setNotifications,
    // Helper methods
    addNotification: (notification) => {
      setNotifications(prev => [...prev, { ...notification, id: Date.now() }]);
    },
    removeNotification: (id) => {
      setNotifications(prev => prev.filter(n => n.id !== id));
    }
  };

  return createElement(AppContext.Provider, { value: contextValue }, children);
}

// Nested providers for different concerns
function App() {
  return createElement(AppProvider, null,
    createElement('div', { className: 'app' },
      createElement(Header),
      createElement(MainContent),
      createElement(Footer)
    )
  );
}

Consumer Component

The Consumer component uses a render prop pattern to access the context value. The child function receives the current context value as its argument.

Consumer Usage Examples:

import { createElement } from 'rax';

// Using Consumer with render prop
function ThemedButton() {
  return createElement(ThemeContext.Consumer, null, (themeContext) => {
    if (!themeContext) {
      return createElement('button', null, 'No theme available');
    }

    return createElement('button', {
      style: {
        backgroundColor: themeContext.theme === 'light' ? '#fff' : '#333',
        color: themeContext.theme === 'light' ? '#333' : '#fff',
        border: `1px solid ${themeContext.theme === 'light' ? '#ccc' : '#666'}`
      },
      onClick: themeContext.toggleTheme
    }, `Switch to ${themeContext.theme === 'light' ? 'dark' : 'light'} mode`);
  });
}

// Multiple context consumers
function UserProfile() {
  return createElement(UserContext.Consumer, null, (userContext) =>
    createElement(ThemeContext.Consumer, null, (themeContext) => {
      if (!userContext.user) {
        return createElement('div', null, 'Please log in');
      }

      return createElement('div', {
        className: `user-profile ${themeContext.theme}`
      },
        createElement('h2', null, userContext.user.name),
        createElement('p', null, `ID: ${userContext.user.id}`),
        createElement('button', {
          onClick: () => userContext.setUser(null)
        }, 'Logout')
      );
    })
  );
}

Context with Hooks

The recommended modern approach is to use useContext hook instead of Consumer components for cleaner code.

Hook-based Context Usage:

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

const AuthContext = createContext();

// Custom hook for easier context consumption
function useAuth() {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
}

function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);

  const login = async (email, password) => {
    setLoading(true);
    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password })
      });
      const userData = await response.json();
      setUser(userData);
    } catch (error) {
      console.error('Login failed:', error);
    } finally {
      setLoading(false);
    }
  };

  const logout = () => {
    setUser(null);
  };

  const value = {
    user,
    loading,
    login,
    logout,
    isAuthenticated: !!user
  };

  return createElement(AuthContext.Provider, { value }, children);
}

// Components using the custom hook
function LoginButton() {
  const { login, loading, isAuthenticated } = useAuth();

  if (isAuthenticated) {
    return createElement('span', null, 'Already logged in');
  }

  const handleLogin = () => {
    login('user@example.com', 'password');
  };

  return createElement('button', {
    onClick: handleLogin,
    disabled: loading
  }, loading ? 'Logging in...' : 'Login');
}

function UserGreeting() {
  const { user, logout } = useAuth();

  if (!user) {
    return createElement('div', null, 'Please log in');
  }

  return createElement('div', null,
    createElement('p', null, `Welcome, ${user.name}!`),
    createElement('button', { onClick: logout }, 'Logout')
  );
}

Context Best Practices

Performance Optimization:

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

const AppContext = createContext();

function AppProvider({ children }) {
  const [user, setUser] = useState(null);
  const [theme, setTheme] = useState('light');

  // Memoize context value to prevent unnecessary re-renders
  const contextValue = useMemo(() => ({
    user,
    setUser,
    theme,
    setTheme
  }), [user, theme]);

  return createElement(AppContext.Provider, { value: contextValue }, children);
}

// Split contexts by concern to minimize re-renders
const UserContext = createContext();
const ThemeContext = createContext();

function UserProvider({ children }) {
  const [user, setUser] = useState(null);
  
  const value = useMemo(() => ({ user, setUser }), [user]);
  
  return createElement(UserContext.Provider, { value }, children);
}

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const value = useMemo(() => ({ theme, setTheme }), [theme]);
  
  return createElement(ThemeContext.Provider, { value }, children);
}

Types

// Context object type
interface Context<T> {
  Provider: ComponentType<ProviderProps<T>>;
  Consumer: ComponentType<ConsumerProps<T>>;
  _contextID: string;
  _defaultValue: T;
  __getNearestParentProvider: Function;
}

// Provider component props
interface ProviderProps<T> {
  value: T;
  children?: RaxNode;
}

// Consumer component props  
interface ConsumerProps<T> {
  children: (value: T) => RaxNode;
}

// Context value type helper
type ContextType<C extends Context<any>> = C extends Context<infer T> ? T : never;

// Custom hook return type
interface UseContextReturn<T> {
  (context: Context<T>): 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