Skip to main content

Hooks and app APIs

React's own hooks come from react and work as they do anywhere: useState, useEffect, useRef, useCallback, useMemo, useReducer, useContext. The runtime services effects and timers once per frame from the host pump, so useEffect and setTimeout behave as you expect. The package adds three hooks of its own.

useAnimatedValue​

const pulse = useAnimatedValue(1);

Creates an Animated.Value tied to the component's lifetime: it is destroyed on unmount. Use it instead of useRef(new Animated.Value(1)).current so the engine-side value is released. See Animated.

usePersistentState​

const [count, setCount] = usePersistentState('count', 0);

useState whose value survives a hot reload in the simulators and the on-device dev loop. You rarely call it: in those loops the bundler rewrites plain useState to this, keyed by component name and hook order, so the state survives transparently. Reach for it directly when you want a key that is explicitly yours. The value must be JSON-serializable. On a device, and in any release build, it is exactly useState. Hot reload explains the keying.

useHostValue​

const steps = useHostValue(0);

Flow B. Declares a number the host feeds into the app. The compiler lowers it to a state slot, and the package names it as an input. The firmware finds it with erb_input_find("steps") and calls erb_input_set_int() whenever the value changes; the app re-renders as if setState had been called. This is how sensor readings, clocks and any other host data reach a compiled app with no JavaScript on the device. In the simulator, where there is no host to write it, it returns its initial value. The RP2040 guide shows it driving a pedometer.

AppRegistry​

import {AppRegistry} from 'embedded-react';
import {App} from './App.jsx';

AppRegistry.registerComponent('my-app', () => App);

Registers the root component and mounts it into a container the size of the screen. In React Native the native side calls runApplication when the activity starts; here running the bundle is starting the app, so registration mounts immediately. The root is created once and reused across hot reloads, which is what lets React reconcile the old tree into the new one in place.

Platform​

Platform.OS is 'embedded'. Platform.select({embedded: a, default: b}) picks by that key, as in React Native, so shared code can branch without a build flag.

The screen global​

const SW = screen.width;
const SH = screen.height;
const COMPACT = SW < 300;

The host injects screen with the panel's width and height in pixels before the app runs. In Flow A it is the real panel (or the simulator's current size). In Flow B, values derived from it are worked out at boot from the real panel, and a branch that changes the tree adds a layout the panel picks at boot, so one build runs on every panel; see the AOT subset. Layout shows the pattern.

Timers and time​

setTimeout, setInterval, clearTimeout and clearInterval are the web ones, driven by the engine's clock and serviced once per frame. Date.now() and performance.now() read the same clock; Date.now() counts from boot until the firmware sets the wall clock from an RTC or NTP. There are no Date objects in the runtime's default profile. Flow B: timestamps are 64-bit integers with the arithmetic rules in the AOT subset.