mediumReact Native#25

Accelerometer sensor subscription

Prompt

Subscribe to the accelerometer using expo-sensors and display the x, y, z values in real time. Clean up the subscription on unmount. Only show values rounded to 2 decimal places.

Solution

const [data, setData] = useState({ x: 0, y: 0, z: 0 })
useEffect(() => {
  const sub = Accelerometer.addListener(({ x, y, z }) => {
    setData({ x: Math.round(x * 100) / 100, y: Math.round(y * 100) / 100, z: Math.round(z * 100) / 100 })
  })
  Accelerometer.setUpdateInterval(100)
  return () => sub.remove()
}, [])
return <Text>x: {data.x} y: {data.y} z: {data.z}</Text>
Mentor's take

A sensor subscription is a firehose wired to your render cycle, and this challenge is really about flow control on the JS thread. Every listener callback is an event crossing from native to JS, and every setData is a re-render. Left at hardware rates that's a render every few milliseconds — so setUpdateInterval(100) is the first decision, throttling at the native side to 10Hz so the JS thread never sees events it would only waste. Pick the rate the UI needs, not the rate the hardware offers; a shake detector might want 50ms, a level indicator is fine at 200ms.

The cleanup is non-negotiable and this is the pattern for every native event source (NetInfo, keyboard, app-state, location): addListener returns a subscription object, and sub.remove() in the effect cleanup severs it on unmount. Skip it and the native side keeps sampling and emitting — battery drain the user notices, plus setState on an unmounted component. On mobile, a leaked subscription isn't just a memory bug; it's a hardware sensor left running.

The rounding is honest about its role: it's display formatting, and it also stabilizes the state values so near-identical readings don't churn renders for invisible changes.

Red flag: subscribing without remove() in cleanup, or leaving the update interval at its default and wondering why the screen janks — both say "I haven't shipped sensor code."

Say it: "Sensor work is flow control: throttle at the native side with setUpdateInterval so the JS thread only sees events it needs, and treat the subscription's remove() in effect cleanup as non-negotiable — it's live hardware, not just memory."