Skip to content

React Native

React Native has fetch built in — no extra dependencies needed.

class VoltaClient {
constructor(apiUrl, apiKey, layoutId) {
this.apiUrl = apiUrl.replace(/\/$/, '');
this.apiKey = apiKey;
this.layoutId = layoutId;
this.token = null;
}
// Step 1: Discover controls
async getLayoutInfo() {
const res = await fetch(`${this.apiUrl}/layout/${this.layoutId}`, {
headers: { 'x-api-key': this.apiKey },
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
// Step 2: Get a token
async connect() {
const res = await fetch(`${this.apiUrl}/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': this.apiKey,
},
body: JSON.stringify({ layoutId: this.layoutId }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const { token } = await res.json();
this.token = token;
}
// Step 3: Send actions
async sendAction(lid, type, value) {
const res = await fetch(`${this.apiUrl}/action`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.token}`,
},
body: JSON.stringify({ layoutId: this.layoutId, lid, type, value }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
sendButton(lid) { return this.sendAction(lid, 'Button'); }
sendSlider(lid, value) { return this.sendAction(lid, 'Slider', value); }
sendToggle(lid, value) { return this.sendAction(lid, 'Toggle', value); }
sendIndex(lid, value) { return this.sendAction(lid, 'Index', value); }
}
import React, { useState, useEffect } from 'react';
import { View, Button, Text } from 'react-native';
const client = new VoltaClient(API_URL, API_KEY, LAYOUT_ID);
export default function VoltaScreen() {
const [controls, setControls] = useState([]);
useEffect(() => {
(async () => {
await client.connect();
const layout = await client.getLayoutInfo();
setControls(layout.controls);
})();
}, []);
return (
<View>
{controls.map((c) => (
<Button
key={c.lid}
title={c.props?.label || c.type}
onPress={() => client.sendButton(c.lid)}
/>
))}
</View>
);
}