foobar
foobar•3mo ago

Data sync input between parent and children

I have the following scheme (cf picture): - a route that get initial data - data with items are sent to an island - item of data are sent to a child island Child islands have only input with no form nor validate button. How to track and sync input change in children and reflect it to parent ?
3 Replies
foobar
foobar•3mo ago
routes/ToDoPage.tsx
export const handler: Handlers = {
async GET(req: Request, ctx: FreshContext) {
//...
// retrieve initial data from a DB (KV)
const initialData = await todo.list();
const res = await ctx.render({
...ctx.state,
initialData,
});
return res;
},
};

export default function ToDoPage(
{ data: { initialData } }: {data: { initialData: Todo[] }},
) {
// Save data modified in DB todos
const save = ()=> { //... }
return (
<>
// Print Todo Items
<ToDos data={initialData} />
</>
);
}
export const handler: Handlers = {
async GET(req: Request, ctx: FreshContext) {
//...
// retrieve initial data from a DB (KV)
const initialData = await todo.list();
const res = await ctx.render({
...ctx.state,
initialData,
});
return res;
},
};

export default function ToDoPage(
{ data: { initialData } }: {data: { initialData: Todo[] }},
) {
// Save data modified in DB todos
const save = ()=> { //... }
return (
<>
// Print Todo Items
<ToDos data={initialData} />
</>
);
}
islands/todos.tsx
export default function ToDos(props: Props) {
const data = useSignal<BenchItem[]>(props.data);
const message = useSignal("");

const addItem = () => {
const item = {
id: data.value.length,
name: "new item",
};
data.value = data.value.concat(item);
};

const change = (item: BenchItem) => {
// ?? code is correct ??
const newData = data.value.filter((x) => x.id !== item.id);
newData.push(item);
data.value = newData;
};

return (
<>
<button class="btn btn-primary" onClick={addItem}>
Add todo
</button>
// ?? Pass a signal item instead ??
{data.value?.map((item) => (
<TodoItem
item={item}
change={change}
/>
))}
</>
);
}
export default function ToDos(props: Props) {
const data = useSignal<BenchItem[]>(props.data);
const message = useSignal("");

const addItem = () => {
const item = {
id: data.value.length,
name: "new item",
};
data.value = data.value.concat(item);
};

const change = (item: BenchItem) => {
// ?? code is correct ??
const newData = data.value.filter((x) => x.id !== item.id);
newData.push(item);
data.value = newData;
};

return (
<>
<button class="btn btn-primary" onClick={addItem}>
Add todo
</button>
// ?? Pass a signal item instead ??
{data.value?.map((item) => (
<TodoItem
item={item}
change={change}
/>
))}
</>
);
}
islands/todoItem.tsx
const TodoItem = ({ item, change }) => {
// ?? use Signal to track change or only trigger a change function ??
const newItem = useSignal(item);

const doChange = useCallback(() => {
// ?? what to do here ??
// infinite loop ?
change(newItem.value);
}, [newItem]);

return (
<>
<input
type="text"
// ?? infinite loop ??
value={newItem.name}
// ?? doChange or link with a signal variable ??
onChange={doChange}
/>
</>
);
};
const TodoItem = ({ item, change }) => {
// ?? use Signal to track change or only trigger a change function ??
const newItem = useSignal(item);

const doChange = useCallback(() => {
// ?? what to do here ??
// infinite loop ?
change(newItem.value);
}, [newItem]);

return (
<>
<input
type="text"
// ?? infinite loop ??
value={newItem.name}
// ?? doChange or link with a signal variable ??
onChange={doChange}
/>
</>
);
};
marvinh.
marvinh.•3mo ago
Remove the newItem signal, it's useless and only complicates the code. The onChange function can directly write into the target signal. There is no need to manually sync state with signals or think in terms of parent or child components. That's the old react way of thinking that's made redundant with signals.
foobar
foobar•3mo ago
Thanks it works. I was a little bit out of date 😄 and I am upgrading with deno/fresh