Skip to content

Commit 6c6e504

Browse files
committed
fix errors in example
1 parent ee30814 commit 6c6e504

1 file changed

Lines changed: 55 additions & 15 deletions

File tree

tsunami/prompts/system.md

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -633,12 +633,20 @@ Best Practices:
633633

634634
## State Management and Async Updates
635635

636-
While React patterns typically avoid globals, in Go Tsunami applications it's perfectly fine and often clearer to use global variables. However, when dealing with async operations and goroutines, special care must be taken:
636+
For global state management, use the atoms system (SharedAtom, Config, or Data as appropriate). This provides global reactive state that components can subscribe to:
637637

638638
```go
639-
// Global state is fine!
640-
var globalTodos []Todo
641-
var globalFilter string
639+
// Use func init() to set atom defaults
640+
func init() {
641+
app.SetData("todos", []Todo{})
642+
app.SetConfig("filter", "")
643+
}
644+
645+
type Todo struct {
646+
Id int `json:"id"`
647+
Text string `json:"text"`
648+
Done bool `json:"done"`
649+
}
642650

643651
// For async operations, consider using a state struct
644652
type TimerState struct {
@@ -649,11 +657,12 @@ type TimerState struct {
649657

650658
var TodoApp = app.DefineComponent("TodoApp",
651659
func(ctx context.Context, _ struct{}) any {
652-
// Local state for UI updates
653-
count, setCount := vdom.UseState(ctx, 0)
660+
// Use atoms for global state (prefixes must match init functions)
661+
todos, setTodos, _ := vdom.UseData[[]Todo](ctx, "todos")
662+
filter, setFilter, _ := vdom.UseConfig[string](ctx, "filter")
654663

655-
// vdom.UseState returns value, setter, and functional setter
656-
seconds, setSeconds, setSecondsFn := vdom.UseState(ctx, 0)
664+
// Local state for async timer demo
665+
seconds, _, setSecondsFn := vdom.UseState[int](ctx, 0)
657666

658667
// Use refs to store complex state that goroutines need to access
659668
stateRef := vdom.UseRef(ctx, &TimerState{
@@ -699,15 +708,43 @@ var TodoApp = app.DefineComponent("TodoApp",
699708

700709
// Use vdom.UseEffect for cleanup on unmount
701710
vdom.UseEffect(ctx, func() func() {
711+
startAsync() // Start the timer when component mounts
702712
return func() {
703713
stopAsync()
704714
}
705715
}, []any{})
706716

707-
return vdom.H("div", nil,
708-
vdom.ForEach(globalTodos, func(todo Todo, idx int) any {
709-
// Use WithKey() for adding keys to components
710-
return TodoItem(TodoItemProps{Todo: todo}).WithKey(idx)
717+
addTodo := func(text string) {
718+
newTodo := Todo{
719+
Id: len(todos) + 1,
720+
Text: text,
721+
Done: false,
722+
}
723+
setTodos(append(todos, newTodo))
724+
}
725+
726+
return vdom.H("div", map[string]any{"className": "todo-app"},
727+
vdom.H("h1", nil, "Todo App"),
728+
vdom.H("p", nil, "Timer: ", seconds, " seconds"),
729+
vdom.H("input", map[string]any{
730+
"placeholder": "Filter todos...",
731+
"value": filter,
732+
"onChange": func(e vdom.VDomEvent) { setFilter(e.TargetValue) },
733+
}),
734+
vdom.H("button", map[string]any{
735+
"onClick": func() { addTodo("New todo") },
736+
}, "Add Todo"),
737+
vdom.ForEach(todos, func(todo Todo, idx int) any {
738+
// Only show todos that contain the filter text
739+
if filter != "" && !strings.Contains(strings.ToLower(todo.Text), strings.ToLower(filter)) {
740+
return nil
741+
}
742+
return vdom.H("div", map[string]any{
743+
"key": todo.Id,
744+
"className": "todo-item",
745+
},
746+
vdom.H("span", nil, todo.Text),
747+
)
711748
}),
712749
)
713750
},
@@ -895,9 +932,12 @@ var App = app.DefineComponent("App",
895932
}
896933

897934
deleteTodo := func(id int) {
898-
newTodos := vdom.Filter(todos, func(todo Todo) bool {
899-
return todo.Id != id
900-
})
935+
newTodos := make([]Todo, 0)
936+
for _, todo := range todos {
937+
if todo.Id != id {
938+
newTodos = append(newTodos, todo)
939+
}
940+
}
901941
setTodos(newTodos)
902942
}
903943

0 commit comments

Comments
 (0)