@json-eval-rs/react-native
v0.0.30
Published
High-performance JSON Logic evaluator with schema validation for React Native
Maintainers
Readme
@json-eval-rs/react-native
High-performance JSON Logic evaluator with schema validation for React Native.
Built with Rust for maximum performance, with native Android (Kotlin + JNI) and iOS (Objective-C++) bindings. All operations run asynchronously on background threads to keep your UI responsive.
Features
- 🚀 Native Performance - Built with Rust for iOS and Android
- ✅ Schema Validation - Validate data against JSON schema rules
- 🔄 Dependency Tracking - Auto-update dependent fields
- 🎯 Type Safe - Full TypeScript support
- ⚛️ React Hooks - Built-in
useJSONEvalhook - 📱 Cross-Platform - Works on iOS and Android
- 🔥 Fast - Native performance, not JavaScript
Installation
yarn install @json-eval-rs/react-nativeOr with Yarn:
yarn add @json-eval-rs/react-nativeiOS
cd ios && pod installAndroid
No additional steps required. The library uses autolinking.
Quick Start
Basic Usage
import { JSONEval } from '@json-eval-rs/react-native';
const schema = {
type: 'object',
properties: {
user: {
type: 'object',
properties: {
name: {
type: 'string',
rules: {
required: { value: true, message: 'Name is required' },
minLength: { value: 3, message: 'Min 3 characters' }
}
},
age: {
type: 'number',
rules: {
minValue: { value: 18, message: 'Must be 18+' }
}
}
}
}
}
};
// Create evaluator
const eval = new JSONEval({ schema });
// Evaluate
const data = { user: { name: 'John', age: 25 } };
const result = await eval.evaluate({ data });
console.log('Evaluated:', result);
// Validate
const validation = await eval.validate({ data });
if (validation.hasError) {
validation.errors.forEach(error => {
console.error(`${error.path}: ${error.message}`);
});
}
// Clean up
await eval.dispose();Using React Hook
import React, { useState } from 'react';
import { View, TextInput, Button, Text } from 'react-native';
import { useJSONEval } from '@json-eval-rs/react-native';
const schema = {
type: 'object',
properties: {
user: {
type: 'object',
properties: {
name: {
type: 'string',
rules: {
required: { value: true, message: 'Name is required' },
minLength: { value: 3, message: 'Min 3 characters' }
}
}
}
}
}
};
function MyForm() {
const eval = useJSONEval({ schema });
const [name, setName] = useState('');
const [errors, setErrors] = useState<string[]>([]);
const handleValidate = async () => {
if (!eval) return;
const data = { user: { name } };
const validation = await eval.validate({ data });
if (validation.hasError) {
setErrors(validation.errors.map(e => e.message));
} else {
setErrors([]);
console.log('Valid!');
}
};
return (
<View>
<TextInput
value={name}
onChangeText={setName}
placeholder="Enter name"
/>
<Button title="Validate" onPress={handleValidate} />
{errors.map((error, i) => (
<Text key={i} style={{ color: 'red' }}>{error}</Text>
))}
</View>
);
}Advanced: Dependent Fields
import React, { useState, useEffect } from 'react';
import { View, TextInput, Text } from 'react-native';
import { useJSONEval } from '@json-eval-rs/react-native';
const schema = {
type: 'object',
properties: {
quantity: { type: 'number' },
price: { type: 'number' },
total: {
type: 'number',
$evaluation: {
'*': [{ var: 'quantity' }, { var: 'price' }]
}
}
}
};
function Calculator() {
const eval = useJSONEval({ schema });
const [quantity, setQuantity] = useState(1);
const [price, setPrice] = useState(10);
const [total, setTotal] = useState(0);
useEffect(() => {
if (!eval) return;
const updateTotal = async () => {
const data = { quantity, price };
const result = await eval.evaluateDependents({
changedPaths: ['quantity'], // Array of changed field paths
data,
reEvaluate: false // Optional: re-evaluate entire schema after dependents
});
setTotal(result.total);
};
updateTotal();
}, [eval, quantity, price]);
return (
<View>
<TextInput
value={String(quantity)}
onChangeText={(val) => setQuantity(Number(val))}
keyboardType="numeric"
/>
<TextInput
value={String(price)}
onChangeText={(val) => setPrice(Number(val))}
keyboardType="numeric"
/>
<Text>Total: {total}</Text>
</View>
);
}API Reference
JSONEval Class
Constructor
constructor(options: {
schema: string | object;
context?: string | object;
data?: string | object;
})Creates a new evaluator instance.
Methods
evaluate(options)
Evaluates the schema with provided data.
async evaluate(options: {
data: string | object;
context?: string | object;
}): Promise<any>validate(options)
Validates data against schema rules.
async validate(options: {
data: string | object;
context?: string | object;
}): Promise<ValidationResult>Returns:
interface ValidationResult {
hasError: boolean;
errors: ValidationError[];
}
interface ValidationError {
path: string;
ruleType: string;
message: string;
}evaluateDependents(options)
Re-evaluates fields that depend on changed paths (processes transitively).
async evaluateDependents(options: {
changedPaths: string[]; // Array of field paths that changed
data?: string | object; // Optional updated data
context?: string | object; // Optional context
reEvaluate?: boolean; // If true, performs full evaluation after dependents
}): Promise<any[]>Parameters:
changedPaths: Array of field paths that changed (e.g.,['field1', 'nested.field2'])data: Optional JSON data (string or object). If provided, replaces current datacontext: Optional context datareEvaluate: Iftrue, performs full schema evaluation after processing dependents (default:false)
Returns: Array of dependent field change objects with $ref, value, $field, $parentField, and transitive properties.
Example:
// Update multiple fields and get their dependents
const result = await eval.evaluateDependents({
changedPaths: ['illustration.insured.ins_dob', 'illustration.product_code'],
data: updatedData,
reEvaluate: true // Re-run full evaluation after dependents
});
// Process the changes
result.forEach(change => {
console.log(`Field ${change.$ref} changed:`, change.value);
});dispose()
Frees native resources. Must be called when done.
async dispose(): Promise<void>static version()
Gets the library version.
static async version(): Promise<string>useJSONEval Hook
React hook for automatic lifecycle management.
function useJSONEval(options: JSONEvalOptions): JSONEval | nullReturns null until initialized, then returns the JSONEval instance.
Automatically disposes on unmount.
Validation Rules
Supported validation rules:
- required - Field must have a value
- minLength / maxLength - String/array length validation
- minValue / maxValue - Numeric range validation
- pattern - Regex pattern matching
Platform Support
- iOS: 11.0+
- Android: API 21+ (Android 5.0)
- React Native: 0.64+
Performance
Typical performance on modern devices:
- Schema parsing: < 5ms
- Evaluation: < 10ms for complex schemas
- Validation: < 5ms
Native performance beats JavaScript-only solutions by 10-50x.
Sequential Processing
This library uses sequential processing by default, which is optimal for mobile devices. The Rust core supports an optional parallel feature using Rayon, but:
- Mobile devices have limited cores and power constraints
- Sequential processing is faster for typical mobile use cases (small to medium datasets)
- Parallel overhead exceeds benefits for arrays < 1000 items
- Battery life is better with sequential processing
The default configuration is optimized for mobile performance and battery efficiency.
Error Handling
All async methods can throw errors:
try {
const result = await eval.evaluate({ data });
} catch (error) {
console.error('Evaluation error:', error.message);
}Memory Management
Always dispose of instances when done:
const eval = new JSONEval({ schema });
try {
// Use eval
} finally {
await eval.dispose(); // Important!
}Or use the hook for automatic management:
function MyComponent() {
const eval = useJSONEval({ schema }); // Auto-disposed on unmount
// Use eval
}TypeScript
Full TypeScript support included. All types are exported:
import type {
JSONEval,
ValidationError,
ValidationResult,
JSONEvalOptions,
EvaluateOptions,
EvaluateDependentsOptions
} from '@json-eval-rs/react-native';Troubleshooting
iOS Build Errors
If you encounter build errors on iOS:
cd ios
rm -rf Pods Podfile.lock
pod install --repo-updateAndroid Build Errors
If you encounter build errors on Android:
cd android
./gradlew clean
cd ..Then rebuild your app.
"Module not found" Error
Make sure you've:
- Installed the package
- Run
pod installon iOS - Rebuilt the app completely
Contributing
See the contributing guide to learn how to contribute to the repository and the development workflow.
License
MIT
Support
- GitHub Issues: https://github.com/byrizki/json-eval-rs/issues
- Documentation: https://github.com/byrizki/json-eval-rs
