Skip to content

Commit 32fb299

Browse files
Making react work
1 parent cbafc98 commit 32fb299

4 files changed

Lines changed: 111 additions & 107 deletions

File tree

playground/internal/react/component.go

Lines changed: 0 additions & 35 deletions
This file was deleted.

playground/internal/react/elements.go

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,6 @@ package react
22

33
import "github.com/gopherjs/gopherjs/js"
44

5-
func StrictMode(children ...Node) *Element {
6-
return CreateElement(react().Get(`StrictMode`), nil, children...)
7-
}
8-
9-
func Fragment(children ...Node) *Element {
10-
return CreateElement(react().Get(`Fragment`), nil, children...)
11-
}
12-
13-
func Div(props Props, children ...Node) *Element {
14-
return CreateElement(`div`, props, children...)
15-
}
16-
17-
func Span(props Props, children ...Node) *Element {
18-
return CreateElement(`span`, props, children...)
19-
}
20-
21-
func P(props Props, children ...Node) *Element {
22-
return CreateElement(`p`, props, children...)
23-
}
24-
25-
func Button(value string, props Props, onClick func()) *Element {
26-
if props == nil {
27-
props = Props{}
28-
}
29-
props[`value`] = value
30-
props[`type`] = `button`
31-
props[`onClick`] = onClick
32-
return CreateElement(`input`, props)
33-
}
34-
35-
//============================================
36-
375
func NewCounter(initName string, initAge int) *Element {
386
return NewComponent(Props{}, map[string]any{
397
`name`: initName,
@@ -43,11 +11,15 @@ func NewCounter(initName string, initAge int) *Element {
4311
CreateElement(`input`, Props{
4412
`value`: c.GetState(`name`).String(),
4513
`onChange`: func(e *js.Object) {
46-
c.SetState(State{`name`: e.Get(`target`).Get(`value`).String()})
14+
c.SetState(map[string]any{
15+
`name`: e.Get(`target`).Get(`value`).String(),
16+
})
4717
},
4818
}),
4919
Button(`Increment age`, nil, func() {
50-
c.SetState(State{`age`: c.GetState(`age`).Int() + 1})
20+
c.SetState(map[string]any{
21+
`age`: c.GetState(`age`).Int() + 1,
22+
})
5123
}),
5224
CreateElement(`p`, nil,
5325
`Hello, `, c.GetState(`name`).String(), `. You are `, c.GetState(`age`).Int(), `.`),

playground/internal/react/react.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ type (
2727
// e.g. { `className`: `greeting` }.
2828
// See: https://react.dev/reference/react/createElement
2929
Props map[string]any
30+
31+
StateMap map[string]any
32+
33+
// Component is a React component used when rendering with state.
34+
// See: https://react.dev/reference/react/Component
35+
Component struct{ *js.Object }
36+
37+
State[T any] struct{ getter, setter *js.Object }
3038
)
3139

3240
func reactDom() *js.Object { return js.Global.Get(`ReactDOM`) }
@@ -57,3 +65,62 @@ func checkNode(n Node) Node {
5765
panic(fmt.Errorf(`unsupported child type %T`, c))
5866
}
5967
}
68+
69+
func NewComponent(props Props, init StateMap, render func(*Component) Node) *Element {
70+
reactComp := react().Get("Component")
71+
ctor := js.MakeFunc(func(this *js.Object, args []*js.Object) any {
72+
reactComp.Call(`call`, props)
73+
this.Set(`state`, init)
74+
return nil
75+
})
76+
rf := js.MakeFunc(func(this *js.Object, args []*js.Object) any {
77+
return render(&Component{Object: this})
78+
})
79+
ctor.Set(`prototype`, reactComp.Get(`prototype`))
80+
ctor.Get(`prototype`).Set(`constructor`, ctor)
81+
ctor.Get("prototype").Set("render", rf)
82+
return &Element{Object: react().Call(`createElement`, ctor)}
83+
}
84+
85+
func (c *Component) GetState(key string) *js.Object {
86+
return c.Get("state").Get(key)
87+
}
88+
89+
func (c *Component) SetState(newState StateMap) {
90+
c.Call("setState", newState)
91+
}
92+
93+
func StrictMode(children ...Node) *Element {
94+
return CreateElement(react().Get(`StrictMode`), nil, children...)
95+
}
96+
97+
func Fragment(children ...Node) *Element {
98+
return CreateElement(react().Get(`Fragment`), nil, children...)
99+
}
100+
101+
func Div(props Props, children ...Node) *Element {
102+
return CreateElement(`div`, props, children...)
103+
}
104+
105+
func Span(props Props, children ...Node) *Element {
106+
return CreateElement(`span`, props, children...)
107+
}
108+
109+
func Button(value string, props Props, onClick func()) *Element {
110+
if props == nil {
111+
props = Props{}
112+
}
113+
props[`value`] = value
114+
props[`type`] = `button`
115+
props[`onClick`] = onClick
116+
return CreateElement(`input`, props)
117+
}
118+
119+
func UseState[T any](initial T) State[T] {
120+
s := react().Call(`useState`, initial)
121+
return State[T]{getter: s.Index(0), setter: s.Index(1)}
122+
}
123+
124+
func (s State[T]) Get() T { return s.getter.Interface().(T) }
125+
126+
func (s State[T]) Set(v T) { s.setter.Invoke(v) }

playground/playground.js

Lines changed: 38 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)