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?
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.
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:
I select an <input> component that is inside my repeating ‘Box’.
I go to that input’s Data tab > “HTML Attributes”.
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)?