---
title: 'React Native'
description: "Configure iOS and Android React Native packages using the native C++ TurboModule JSI bridge."
navigation:
  icon: 'i-simple-icons-react'
seo:
  title: 'React Native'
  description: "Configure iOS and Android React Native packages using the native C++ TurboModule JSI bridge."
---

# Using JSONEval-Rs in React Native

The `@json-eval-rs/react-native` package binds directly to the C++ bindings through JSI. This sidesteps standard bridge serialization and avoids stuttering the Native UI thread during large calculations.

## Installation

```bash
yarn add @json-eval-rs/react-native
# or
npm install @json-eval-rs/react-native
```

### iOS Setup
```bash
cd ios && pod install
```

## Built-in BigInt Support

Standard JS engines chop off precision for integers extending beyond `Number.MAX_SAFE_INTEGER`. To bypass this, JSONEval processes large variables inside its JavaScript bindings using native `BigInt`.

## Usage Examples

The package includes a custom React hook that mirrors core engine capabilities.

### 1. Basic Form Input Validation

Use `useJSONEval` to automatically clean up C++ binding allocations upon unloading a screen.

```typescript
import React, { useState } from 'react';
import { View, Text, TextInput } from 'react-native';
import { useJSONEval } from '@json-eval-rs/react-native';

const schema = {
  type: 'object',
  properties: {
    username: {
      type: 'string',
      rules: {
        required: { value: true, message: 'Username required' },
        minLength: { value: 3, message: 'Min 3 chars' }
      }
    }
  }
};

export default function SignupForm() {
  const [data, setData] = useState({ username: '' });
  const [errors, setErrors] = useState({});
  
  // Initialize evaluator instance
  const evalInstance = useJSONEval({ schema });

  const handleChange = async (text: string) => {
    const newData = { username: text };
    setData(newData);

    if (evalInstance) {
      const validation = await evalInstance.validate({ 
        data: JSON.stringify(newData) 
      });
      
      setErrors(validation.errors || {});
    }
  };

  return (
    <View>
      <TextInput 
        value={data.username}
        onChangeText={handleChange}
        placeholder="Username"
      />
      {errors.username && (
        <Text style={{color: 'red'}}>{errors.username.message}</Text>
      )}
    </View>
  );
}
```

### 2. Fetching Schema by Specific Path

You should rarely extract the complete schema into JS just to read a single property. Use specific path retrieval to save CPU loops.

```typescript
const resolveSpecificDiscount = async () => {
  // Pre-evaluate the whole logic 
  await evalInstance.evaluate({ data: JSON.stringify(currentData) });

  // Get exactly the evaluated schema component needed
  const specificPathResult = await evalInstance.getEvaluatedSchemaByPath({
    path: "#/properties/hidden_discount",
    skipLayout: true
  });
  
  // E.g. Apply dynamically
  if (!specificPathResult.hidden) {
    setDiscountState(specificPathResult.value);
  }
};
```

### 3. Subform / Dynamic Array Execution

If you display lists (like FlatList entries or Shopping Cart items), re-evaluating the parent form when one item updates destroys battery life and JS thread frames. Use Subforms targeting identical isolated nodes.

```typescript
const handleItemUpdate = async (itemIndex: number, itemData: any) => {
  const subformPath = "#/shopping_cart_items"; // Path to your array elements
  
  // Check if Engine allocated memory limits structure
  if (await evalInstance.hasSubform(subformPath)) {
      
      // 1. Evaluate only the single array item
      await evalInstance.evaluateSubform({
         subformPath,
         data: itemData
      });

      // 2. Query values generated strictly within that array item scope
      const updatedTotal = await evalInstance.getEvaluatedSchemaByPathSubform({
         subformPath,
         path: "#/properties/item_total" // Evaluated internal structure
      });

      console.log('Update Specific Total: ', updatedTotal.value);
  }
};
```

## Core API Reference

The `JSONEval` base class implements identical native functions available in WebAssembly, but leveraging JSI pointers. Note that invoking `JSONEval.dispose()` is required if wrapping the class directly in Zustand, Redux, or vanilla JS outside `useJSONEval()`.

- **`validate({ data, paths? })`** and **`evaluate({ data, paths? })`**: The primary runners returning full context structures.
- **`validatePaths({ data, paths })`**: Targeted validation for one or two nested property fields skipping broader tree executions.
- **`evaluateOnly({ data })`**: Evaluates but returns `void`, useful to load the Rust side memory before accessing values specifically via Getters.
- **`compileLogic(logicString)` / `runLogic(logicId, data)`**: Isolated execution for generic JSONLogic commands. 

#### Schema Getters

- `getEvaluatedSchema(skipLayout: boolean)`
- `getEvaluatedSchemaByPath({ path, skipLayout })`
- `getSchemaValueArray()` vs `getSchemaValueObject()`

#### Subforms Getters API Suite
Every primary method has an identical replica suffix for Subform usages isolated context scopes:
- `validateSubform()`
- `evaluateDependentsSubform()` 
- `resolveLayoutSubform()`
- `getEvaluatedSchemaByPathSubform()`

## Troubleshooting

### "Native module not found"
-   Ensure you ran `pod install` in the `ios` directory.
-   Rebuild the app (`yarn android` or `yarn ios`).
-   Verify you are not using Expo Go (custom native C++ code requires Development Build or bare workflow).

### JSI Errors
-   This library uses raw JSI bridging. Ensure you have Reanimated installed cleanly if resolving obscure threading crashes (since Reanimated dominates early JSI initialization in Metro).
-   Reloading the Metro bundler completely (`r` then `r` or clearing cache `yarn start -c`) often fixes JSI binding stale references.
