A universal React-compatible render engine for building applications across multiple platforms
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
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)
)
);
}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)
)
);
}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')
);
})
);
}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')
);
}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);
}// 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