Repeat for Each Not Reacting to State Changes in Builder.io

Hi Builder.io Team,

I’m stuck on a data-binding issue in my Next.js (v14) app and hope you can help.

Goal:
I want to display a list of filaments fetched from my Vercel API using a “Repeat for each” block in Builder.

Setup:

  • Next.js app on Vercel using pages/[[...page]].js.

  • Vercel API at /api/admin/inventory/getFilaments works perfectly and returns JSON:

[{"id":"LN997...", "colorName":"Test Red"}]

  • On my /admin/operations page, I use this code in the Edit Content JS + CSS box to fetch data:
import { useState, useEffect } from 'react';

// Use React state
const [filamentsList, setFilamentsList] = useState([]);

// Connect to Builder's state
state.filamentsList = filamentsList;

// Fetch data on load
useEffect(() => {
  const BASE_URL = window.location.origin;

  fetch(`${BASE_URL}/api/admin/inventory/getFilaments`)
    .then(res => res.json())
    .then(data => {
      console.log("Filaments data fetched:", data);
      setFilamentsList(data); // <-- Use the setter
    })
    .catch(error => console.error("Error fetching filaments:", error));
}, []);

The Problem:
I have a Box element with “Repeat for each” set to state.filamentsList, but it renders nothing (blank list).

The Proof:
If I add a separate Text element bound to:

state.filamentsList[0].colorName

it correctly displays “Test Red.”

Question:
The data is clearly being fetched, and the state is being updated (as the Text element proves). Why does the Text element react to the state change, but the Repeat for each block does not? How can I force the repeater to update when state.filamentsList changes?
I suspect this might be related to how state is being updated in the “JS + CSS” box. I’ve tried directly assigning to state.filamentsList = [...], but the repeater still doesn’t update. Could this be a reactivity issue with Builder.io’s Repeat component when the state changes?

Thank you!

Public API Key: 590b8fc7fe6f4f9590676376cdbf6d01

Hi @Cyrus-Gilani

The Repeat for each binding in Builder only re-renders when it detects that the reference of the bound array changes. In your setup, state.filamentsList is assigned only once (at component mount), and while the React state filamentsList updates, Builder doesn’t “see” that as a new array unless you explicitly assign it again inside your effect.

Use this in your “Edit Content JS + CSS” box:

import { useState, useEffect } from 'react';

const [filamentsList, setFilamentsList] = useState([]);

useEffect(() => {
  const BASE_URL = window.location.origin;

  fetch(`${BASE_URL}/api/admin/inventory/getFilaments`)
    .then(res => res.json())
    .then(data => {
      console.log("Filaments data fetched:", data);

      // Update both React and Builder state
      setFilamentsList(data);
      state.filamentsList = [...data]; // <-- trigger Builder reactivity
    })
    .catch(error => console.error("Error fetching filaments:", error));
}, []);

This should get it working. Let me know if there is anything else I can help you with.

1 Like

Hi Sheema,

Thank you so much! That was exactly it. Using state.filamentsList = [...data]; immediately fixed the reactivity issue.

I’m now seeing the correct number of blank rows (two, in my case), so the repeater is definitely working.

I’m stuck on the final step: binding the data inside the repeater. Here’s exactly what I’m doing:

  1. I select an <input> component that is inside my repeating ‘Box’.

  2. I go to that input’s Data tab > “HTML Attributes”.

  3. I add an attribute: Name = value, Value (binding) = item.material.
    Note, this also causes that binding to show for that input in the data tab.

This causes a ReferenceError: item is not defined in the console. (I’ve also tried index with state.filamentsList[index].material, but that gives a ReferenceError: index is not defined).

To be clear, I am setting up the repeater on the ‘Box’ component using the Data tab > “Element data bindings” > “Repeat for each” = state.filamentsList. My component’s Options tab does not have the “Item alias” or “Item variable name” field I’ve seen in other tutorials.

When using the “Element data bindings” method to create a repeater, what is the correct local variable name to access the data for each row (e.g., item.material)?

Thanks again for your help!

Could you please clarify the correct local variable to access the data? Thank you

@sheema

@manish-sharma