11package react
22
33import (
4- "fmt "
4+ "errors "
55
66 "github.com/gopherjs/gopherjs/js"
77)
@@ -29,18 +29,12 @@ type (
2929 Props map [string ]any
3030
3131 // State is a value managed by React's useState hook.
32- // If the component function hasn't been called yet,
33- // the initial value is used and updated until the component is rendered.
34- // After the component is rendered, the value is managed by React.
3532 // See: https://react.dev/reference/react/useState
3633 //
3734 // NOTE: Some types like `State[int]` must instead be `State[float64]`,
3835 // and `State[[]*foo]` must instead be `State[[]any]`, because of
3936 // how the underlying React hook works.
40- State [T any ] struct {
41- initial T
42- getter , setter * js.Object
43- }
37+ State [T any ] struct { getter , setter * js.Object }
4438
4539 // Ref is a React ref created with UseRef().
4640 // It is a mutable object with a `current` property that can hold any value.
@@ -63,6 +57,11 @@ type (
6357 // See: https://react.dev/reference/react-dom/client/createRoot
6458)
6559
60+ var (
61+ ErrStateNotInitialized = errors .New ("react: State not initialized" )
62+ ErrRefNotInitialized = errors .New ("react: Ref not initialized" )
63+ )
64+
6665func reactDom () * js.Object { return js .Global .Get (`ReactDOM` ) }
6766func react () * js.Object { return js .Global .Get (`React` ) }
6867
@@ -128,51 +127,38 @@ func Button(value string, props Props, onClick func(e *js.Object)) *Element {
128127 return CreateElement (`input` , props )
129128}
130129
131- // NewState creates a new State with the given initial value.
132- // The initial value is only used before the component function is called
133- // for the first time. After that, the value is managed by React.
134- // See: https://react.dev/reference/react/useState
135- func NewState [T any ](initial T ) * State [T ] {
136- fmt .Printf ("NewState called [%T]\n " , initial ) // TODO(grantnelson-wf): REMOVE
137- return & State [T ]{initial : initial }
130+ // Add merges another Props into this one.
131+ func (p Props ) Add (other Props ) Props {
132+ if p == nil {
133+ p = Props {}
134+ }
135+ for k , v := range other {
136+ p [k ] = v
137+ }
138+ return p
138139}
139140
140- // Use initializes the state for the current component render.
141+ // UseState creates a state for the current component render.
141142// It must be called unconditionally at the top level of the component function.
142- // This takes the place of calling React's UseState so that the state can be
143- // created outside of the component function.
144143// See: https://react.dev/reference/react/useState
145- func (s * State [T ]) Use () {
146- fmt .Printf ("Use called [%T]\n " , s .initial ) // TODO(grantnelson-wf): REMOVE
147- r := react ().Call (`useState` , s .initial )
148- s .getter = r .Index (0 )
149- s .setter = r .Index (1 )
144+ func UseState [T any ](initial T ) * State [T ] {
145+ r := react ().Call (`useState` , initial )
146+ return & State [T ]{getter : r .Index (0 ), setter : r .Index (1 )}
150147}
151148
152149func (s * State [T ]) Get () T {
153- if s != nil {
154- if s .getter != nil {
155- fmt .Printf ("Get called via getter [%T]\n " , s .initial ) // TODO(grantnelson-wf): REMOVE
156- return s .getter .Interface ().(T )
157- }
158- fmt .Printf ("Get called without getter [%T]\n " , s .initial ) // TODO(grantnelson-wf): REMOVE
159- return s .initial
150+ if s != nil && s .getter != nil {
151+ return s .getter .Interface ().(T )
160152 }
161- var zero T
162- fmt .Printf ("Get called on nil [%T]\n " , zero ) // TODO(grantnelson-wf): REMOVE
163- return zero
153+ panic (ErrStateNotInitialized )
164154}
165155
166156func (s * State [T ]) Set (v T ) {
167- if s != nil {
168- if s .setter != nil {
169- fmt .Printf ("Set called with setter [%T]\n " , s .initial ) // TODO(grantnelson-wf): REMOVE
170- s .setter .Invoke (v )
171- return
172- }
173- fmt .Printf ("Set called without setter [%T]\n " , s .initial ) // TODO(grantnelson-wf): REMOVE
174- s .initial = v
157+ if s != nil && s .setter != nil {
158+ s .setter .Invoke (v )
159+ return
175160 }
161+ panic (ErrStateNotInitialized )
176162}
177163
178164// UseRef creates a mutable ref object that persists for the lifetime of the component.
@@ -183,7 +169,10 @@ func UseRef() *Ref {
183169}
184170
185171func (r * Ref ) Current () * js.Object {
186- return r .holder .Get (`current` )
172+ if r != nil && r .holder != nil {
173+ return r .holder .Get (`current` )
174+ }
175+ panic (ErrRefNotInitialized )
187176}
188177
189178func (r * Ref ) Get (key string ) * js.Object {
@@ -198,10 +187,34 @@ func (r *Ref) Call(name string, args ...any) {
198187 r .Current ().Call (name , args ... )
199188}
200189
190+ // UseEffectNoDeps registers an effect function that is called after every render.
191+ // See: https://react.dev/reference/react/useEffect
192+ func UseEffectNoDeps (effect func ()) {
193+ react ().Call (`useEffect` , effect )
194+ }
195+
201196// UseEffect registers an effect function that is called after rendering.
202197// The effect is re-run whenever any of the dependencies change.
203- // If no dependencies are provided, the effect is only run once after the initial render.
198+ // If no dependency are provided, the effect is only run once after the initial render.
204199// See: https://react.dev/reference/react/useEffect
205200func UseEffect (effect func (), deps ... any ) {
206201 react ().Call (`useEffect` , effect , deps )
207202}
203+
204+ // UseEffectNoDepsWithCleanup registers an effect function that is called after every render.
205+ // The effect function returns a cleanup function that is called before the effect
206+ // is re-run or when the component is unmounted.
207+ // See: https://react.dev/reference/react/useEffect
208+ func UseEffectNoDepsWithCleanup (effect func () func ()) {
209+ react ().Call (`useEffect` , effect )
210+ }
211+
212+ // UseEffectWithCleanup registers an effect function that is called after rendering.
213+ // The effect is re-run whenever any of the dependencies change.
214+ // If no dependency are provided, the effect is only run once after the initial render.
215+ // The effect function returns a cleanup function that is called before the effect
216+ // is re-run or when the component is unmounted.
217+ // See: https://react.dev/reference/react/useEffect
218+ func UseEffectWithCleanup (effect func () func (), deps ... any ) {
219+ react ().Call (`useEffect` , effect , deps )
220+ }
0 commit comments