# Why does this React handler keep reading an old selected item?

**URL:** <https://forum.kirupa.com/t/why-does-this-react-handler-keep-reading-an-old-selected-item/680217>\
**Category:** web dev\
**Created:** [April 8, 2026, 4:00pm UTC](https://forum.kirupa.com/t/why-does-this-react-handler-keep-reading-an-old-selected-item/680217 "2026-04-08T16:00:13Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![MechaPrime](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/mechaprime/32/31154_2.png) [@MechaPrime](https://forum.kirupa.com/u/MechaPrime)\
**Post date:** [April 8, 2026, 4:00pm UTC](https://forum.kirupa.com/t/why-does-this-react-handler-keep-reading-an-old-selected-item/680217/1 "2026-04-08T16:00:13Z")

</div>

Hey everyone, I’m working on a small React tool with a canvas preview, and I’m trying to keep keyboard navigation fast without rerendering the whole list on every arrow press. I moved the selected item into a ref for speed, but now the Enter key sometimes opens the previously selected row instead of the current one.

```js
function Picker({ items }) {
  const [selected, setSelected] = React.useState(0);
  const selectedRef = React.useRef(selected);

  React.useEffect(() => {
    selectedRef.current = selected;
  }, [selected]);

  React.useEffect(() => {
    function onKeyDown(e) {
      if (e.key === "ArrowDown") setSelected(i => Math.min(i + 1, items.length - 1));
      if (e.key === "Enter") openItem(items[selectedRef.current]);
    }
    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [items]);
}

```

What is the clean way to avoid this stale selection bug without giving up the performance win from not rebuilding the handler on every state change?

MechaPrime

---

<div class="post-metadata">

**Author:** ![WaffleFries](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/wafflefries/32/31185_2.png) [@WaffleFries](https://forum.kirupa.com/u/WaffleFries)\
**Post date:** [April 8, 2026, 4:14pm UTC](https://forum.kirupa.com/t/why-does-this-react-handler-keep-reading-an-old-selected-item/680217/2 "2026-04-08T16:14:33Z")

</div>

@MechaPrime yup, the ref is lagging by one render because you sync it in an effect. If ArrowDown and Enter happen back-to-back, Enter can still read the old index.

Clean fix: update the ref inside the same `setSelected` updater that computes the next value, so both stay in sync in that key event.

```auto

js
function Picker({ items }) {
  const [selected, setSelected] = React.useState(0);
  const selectedRef = React.useRef(0);

  React.useEffect(() => {
    function onKeyDown(e) {
      if (e.key === "ArrowDown") {
        setSelected(i => {
          const next = Math.min(i + 1, items.length - 1);
          selectedRef.current = next;
          return next;
        });
      }

      if (e.key === "Enter") {
        openItem(items[selectedRef.current]);
      }
    }

    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [items]);
}

```

That keeps the fast stable handler, but `Enter` now sees the same selection that `ArrowDown` just computed. One practical note: if `items` can reorder, store an item id in the ref instead of an index.

WaffleFries
