From b6bd085e3fc5cf7973c5a8b943a69981270fbd96 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 30 Oct 2019 11:06:39 -0700 Subject: [PATCH 01/17] Implement useState --- lib/react_client/react_interop.dart | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/react_client/react_interop.dart b/lib/react_client/react_interop.dart index 90e7f797..4be99e2c 100644 --- a/lib/react_client/react_interop.dart +++ b/lib/react_client/react_interop.dart @@ -117,6 +117,26 @@ ReactJsComponentFactoryProxy forwardRef(Function(Map props, Ref ref) wrapperFunc @JS('React.forwardRef') external ReactClass _jsForwardRef(Function(JsMap props, JsRef ref) wrapperFunction); +@JS('React.useState') +external List _jsUseState(dynamic value); + +class StateHook { + T _value; + + void Function(dynamic) _setValue; + + StateHook(T initialValue) { + final result = _jsUseState(initialValue); + _value = result[0]; + _setValue = result[1]; + } + + T get value => _value; + void set(T newValue) => _setValue(newValue); +} + +StateHook useState(T initialValue) => new StateHook(initialValue); + abstract class ReactDom { static Element findDOMNode(object) => ReactDOM.findDOMNode(object); static ReactComponent render(ReactElement component, Element element) => ReactDOM.render(component, element); From 0a78d125d9cee1a2f6f7ec7aac050328945d4008 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 30 Oct 2019 11:28:36 -0700 Subject: [PATCH 02/17] Implement useStateInit --- lib/react_client/react_interop.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/react_client/react_interop.dart b/lib/react_client/react_interop.dart index 4be99e2c..5f64b380 100644 --- a/lib/react_client/react_interop.dart +++ b/lib/react_client/react_interop.dart @@ -131,11 +131,19 @@ class StateHook { _setValue = result[1]; } + StateHook.init(T init()) { + final result = _jsUseState(init); + _value = result[0]; + _setValue = result[1]; + } + T get value => _value; void set(T newValue) => _setValue(newValue); + void setTx(T computeNewValue(T oldValue)) => _setValue(computeNewValue); } StateHook useState(T initialValue) => new StateHook(initialValue); +StateHook useStateInit(T init()) => new StateHook.init(init); abstract class ReactDom { static Element findDOMNode(object) => ReactDOM.findDOMNode(object); From 9ee8ff8ded2eda6f238230aa7becd0abdb3abdce Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 30 Oct 2019 11:57:39 -0700 Subject: [PATCH 03/17] Add useState example --- example/test/function_component_test.dart | 31 +++++++++++------------ example/test/react_test_components.dart | 10 -------- lib/react.dart | 2 +- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/example/test/function_component_test.dart b/example/test/function_component_test.dart index 5243d681..67522ca9 100644 --- a/example/test/function_component_test.dart +++ b/example/test/function_component_test.dart @@ -4,28 +4,27 @@ import 'package:react/react.dart' as react; import 'package:react/react_dom.dart' as react_dom; import 'package:react/react_client.dart'; -import 'react_test_components.dart'; +var useStateTestFunctionalComponent = +react.registerFunctionComponent(UseStateTestComponent, displayName: 'useStateTest'); + +UseStateTestComponent(Map props) { + final count = react.useState(0); + + return react.div({}, [ + count.value, + react.button({'onClick': (_) => count.set(0)}, ['Reset']), + react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), + ]); +} void main() { setClientConfiguration(); - var inputValue = 'World'; - // TODO: replace this with hooks/useState when they are added. + render() { react_dom.render( react.Fragment({}, [ - react.input( - { - 'defaultValue': inputValue, - 'onChange': (event) { - inputValue = event.currentTarget.value; - render(); - } - }, - ), - react.br({}), - helloGregFunctionComponent({'key': 'greg'}), - react.br({}), - helloGregFunctionComponent({'key': 'not greg'}, inputValue) + react.h2({'key': 'useStateTestLabel'}, ['useState Hook Test']), + useStateTestFunctionalComponent({'key': 'useStateTest'}, []) ]), querySelector('#content')); } diff --git a/example/test/react_test_components.dart b/example/test/react_test_components.dart index 62163a56..7bf44389 100644 --- a/example/test/react_test_components.dart +++ b/example/test/react_test_components.dart @@ -392,16 +392,6 @@ class _NewContextTypeConsumerComponent extends react.Component2 { } } -var helloGregFunctionComponent = react.registerFunctionComponent(HelloGreg, displayName: 'HelloGreg'); - -HelloGreg(Map props) { - var content = ['Hello Greg!']; - if (props['children'].isNotEmpty) { - content = ['Hello ' + props['children'].join(' ') + '!']; - } - return react.Fragment({}, content); -} - class _Component2TestComponent extends react.Component2 with react.TypedSnapshot { get defaultProps => {'defaultProp': true}; diff --git a/lib/react.dart b/lib/react.dart index 7c68baaa..80188b49 100644 --- a/lib/react.dart +++ b/lib/react.dart @@ -15,7 +15,7 @@ import 'package:react/react_client/react_interop.dart'; import 'package:react/src/context.dart'; export 'package:react/src/context.dart'; -export 'package:react/react_client/react_interop.dart' show forwardRef, createRef; +export 'package:react/react_client/react_interop.dart' show forwardRef, createRef, useState, useStateInit; typedef Error PropValidator( TProps props, String propName, String componentName, String location, String propFullName); From 7c7d6b88735ed318cf21abdade19c956402be229 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 30 Oct 2019 13:52:34 -0700 Subject: [PATCH 04/17] Add doc comments --- example/test/function_component_test.dart | 4 +- lib/react_client/react_interop.dart | 68 +++++++++++++++++++---- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/example/test/function_component_test.dart b/example/test/function_component_test.dart index 67522ca9..8f1191e0 100644 --- a/example/test/function_component_test.dart +++ b/example/test/function_component_test.dart @@ -4,7 +4,7 @@ import 'package:react/react.dart' as react; import 'package:react/react_dom.dart' as react_dom; import 'package:react/react_client.dart'; -var useStateTestFunctionalComponent = +var useStateTestFunctionComponent = react.registerFunctionComponent(UseStateTestComponent, displayName: 'useStateTest'); UseStateTestComponent(Map props) { @@ -24,7 +24,7 @@ void main() { react_dom.render( react.Fragment({}, [ react.h2({'key': 'useStateTestLabel'}, ['useState Hook Test']), - useStateTestFunctionalComponent({'key': 'useStateTest'}, []) + useStateTestFunctionComponent({'key': 'useStateTest'}, []) ]), querySelector('#content')); } diff --git a/lib/react_client/react_interop.dart b/lib/react_client/react_interop.dart index 5f64b380..eaca6a27 100644 --- a/lib/react_client/react_interop.dart +++ b/lib/react_client/react_interop.dart @@ -41,6 +41,9 @@ abstract class React { external static ReactClass get Fragment; external static JsRef createRef(); + external static ReactClass forwardRef(Function(JsMap props, JsRef ref) wrapperFunction); + + external static List useState(dynamic value); } /// Creates a [Ref] object that can be attached to a [ReactElement] via the ref prop. @@ -105,7 +108,7 @@ class JsRef { /// /// See: . ReactJsComponentFactoryProxy forwardRef(Function(Map props, Ref ref) wrapperFunction) { - var hoc = _jsForwardRef(allowInterop((JsMap props, JsRef ref) { + var hoc = React.forwardRef(allowInterop((JsMap props, JsRef ref) { final dartProps = JsBackedMap.backedBy(props); final dartRef = Ref.fromJs(ref); return wrapperFunction(dartProps, dartRef); @@ -114,35 +117,80 @@ ReactJsComponentFactoryProxy forwardRef(Function(Map props, Ref ref) wrapperFunc return new ReactJsComponentFactoryProxy(hoc, shouldConvertDomProps: false); } -@JS('React.forwardRef') -external ReactClass _jsForwardRef(Function(JsMap props, JsRef ref) wrapperFunction); - -@JS('React.useState') -external List _jsUseState(dynamic value); - +/// The return value of [useState]. +/// +/// The current value of the state variable is available via [value] and +/// functions to update it are available via [set] and [setTx]. class StateHook { + /// The first item of the pair returned by [React.useState]. T _value; + /// The second item in the pair returned by [React.useState]. void Function(dynamic) _setValue; StateHook(T initialValue) { - final result = _jsUseState(initialValue); + final result = React.useState(initialValue); _value = result[0]; _setValue = result[1]; } StateHook.init(T init()) { - final result = _jsUseState(init); + final result = React.useState(allowInterop(init)); _value = result[0]; _setValue = result[1]; } + /// The current value of the state variable. T get value => _value; + + /// Updates [value] to [newValue]. void set(T newValue) => _setValue(newValue); - void setTx(T computeNewValue(T oldValue)) => _setValue(computeNewValue); + + /// Updates [value] to the return value of [computeNewValue]. + /// + /// See: . + void setTx(T computeNewValue(T oldValue)) => _setValue(allowInterop(computeNewValue)); } +/// When called inside a [DartFunctionComponent], adds a local state to the component. +/// +/// Returns a [StateHook] with [StateHook.value] initialized to [initialValue]. +/// +/// __Example__: +/// +/// UseStateTestComponent(Map props) { +/// final count = react.useState(0); +/// +/// return react.div({}, [ +/// count.value, +/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), +/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), +/// ]); +/// } +/// +/// Learn more: . StateHook useState(T initialValue) => new StateHook(initialValue); + +/// When called inside a [DartFunctionComponent], adds a local state to the component. +/// +/// Returns a [StateHook] with [StateHook.value] initialized to the return value of [init]. +/// +/// __Example__: +/// +/// UseStateTestComponent(Map props) { +/// final count = react.useStateInit(() { +/// var initialState = someExpensiveComputation(props); +/// return initialState; +/// })); +/// +/// return react.div({}, [ +/// count.value, +/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), +/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), +/// ]); +/// } +/// +/// Learn more: . StateHook useStateInit(T init()) => new StateHook.init(init); abstract class ReactDom { From 904044ba427e2e707384bd35d977abfc92302ba0 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 30 Oct 2019 14:52:28 -0700 Subject: [PATCH 05/17] Add tests --- example/test/function_component_test.dart | 3 +- test/lifecycle_test.dart | 76 +++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/example/test/function_component_test.dart b/example/test/function_component_test.dart index 8f1191e0..c3fb2598 100644 --- a/example/test/function_component_test.dart +++ b/example/test/function_component_test.dart @@ -4,8 +4,7 @@ import 'package:react/react.dart' as react; import 'package:react/react_dom.dart' as react_dom; import 'package:react/react_client.dart'; -var useStateTestFunctionComponent = -react.registerFunctionComponent(UseStateTestComponent, displayName: 'useStateTest'); +var useStateTestFunctionComponent = react.registerFunctionComponent(UseStateTestComponent, displayName: 'useStateTest'); UseStateTestComponent(Map props) { final count = react.useState(0); diff --git a/test/lifecycle_test.dart b/test/lifecycle_test.dart index e2002a96..360bde19 100644 --- a/test/lifecycle_test.dart +++ b/test/lifecycle_test.dart @@ -6,12 +6,14 @@ library lifecycle_test; import 'dart:async'; import 'dart:convert'; import 'dart:html'; +import 'dart:html' as prefix1; import 'dart:js'; import "package:js/js.dart"; import 'package:meta/meta.dart'; import 'package:react/react.dart' as react; import 'package:react/react_client.dart'; +import 'package:react/react_client.dart' as prefix0; import 'package:react/react_client/js_backed_map.dart'; import 'package:react/react_client/react_interop.dart' as react_interop; import 'package:react/react_dom.dart' as react_dom; @@ -509,6 +511,80 @@ main() { sharedTypeTests(testTypeValue); }); + + group('- Hook useState:', () { + ReactDartFunctionComponentFactoryProxy UseStateTest; + DivElement textRef; + DivElement countRef; + ButtonElement setButtonRef; + ButtonElement setTxButtonRef; + + setUpAll(() { + UseStateTest = react.registerFunctionComponent((Map props) { + final text = react.useStateInit(() { + return 'initialValue'; + }); + final count = react.useState(0); + + return react.div({}, [ + react.div({ + 'ref': (ref) { + textRef = ref; + }, + }, [ + text.value + ]), + react.div({ + 'ref': (ref) { + countRef = ref; + }, + }, [ + count.value + ]), + react.button({ + 'onClick': (_) => text.set('newValue'), + 'ref': (ref) { + setButtonRef = ref; + }, + }, [ + 'Set' + ]), + react.button({ + 'onClick': (_) => count.setTx((prev) => prev + 1), + 'ref': (ref) { + setTxButtonRef = ref; + }, + }, [ + '+' + ]), + ]); + }); + + react_dom.render(UseStateTest({}, []), mountNode); + }); + + tearDownAll(() { + UseStateTest = null; + }); + + test('useState initializes state correctly', () { + expect(countRef.text, '0'); + }); + + test('useState Init initializes state correctly', () { + expect(textRef.text, 'initialValue'); + }); + + test('StateHook.set updates state correctly', () { + react_test_utils.Simulate.click(setButtonRef); + expect(textRef.text, 'newValue'); + }); + + test('StateHook.setTx updates state correctly', () { + react_test_utils.Simulate.click(setTxButtonRef); + expect(countRef.text, '1'); + }); + }); }, tags: ['functionComponent']); }); } From 7d0eb8d7e66f0780daf6d319f38d431109d303f5 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 30 Oct 2019 14:58:12 -0700 Subject: [PATCH 06/17] Update comments --- lib/react_client/react_interop.dart | 10 ++++++++-- test/lifecycle_test.dart | 2 -- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/react_client/react_interop.dart b/lib/react_client/react_interop.dart index eaca6a27..ade41d88 100644 --- a/lib/react_client/react_interop.dart +++ b/lib/react_client/react_interop.dart @@ -119,8 +119,10 @@ ReactJsComponentFactoryProxy forwardRef(Function(Map props, Ref ref) wrapperFunc /// The return value of [useState]. /// -/// The current value of the state variable is available via [value] and +/// The current value of the state is available via [value] and /// functions to update it are available via [set] and [setTx]. +/// +/// Learn more: . class StateHook { /// The first item of the pair returned by [React.useState]. T _value; @@ -140,10 +142,14 @@ class StateHook { _setValue = result[1]; } - /// The current value of the state variable. + /// The current value of the state. + /// + /// See: . T get value => _value; /// Updates [value] to [newValue]. + /// + /// See: . void set(T newValue) => _setValue(newValue); /// Updates [value] to the return value of [computeNewValue]. diff --git a/test/lifecycle_test.dart b/test/lifecycle_test.dart index 360bde19..c96408a5 100644 --- a/test/lifecycle_test.dart +++ b/test/lifecycle_test.dart @@ -6,14 +6,12 @@ library lifecycle_test; import 'dart:async'; import 'dart:convert'; import 'dart:html'; -import 'dart:html' as prefix1; import 'dart:js'; import "package:js/js.dart"; import 'package:meta/meta.dart'; import 'package:react/react.dart' as react; import 'package:react/react_client.dart'; -import 'package:react/react_client.dart' as prefix0; import 'package:react/react_client/js_backed_map.dart'; import 'package:react/react_client/react_interop.dart' as react_interop; import 'package:react/react_dom.dart' as react_dom; From 86a7205cc9e5b0a7080fbfb2a6680662bbd77d9e Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 30 Oct 2019 15:04:33 -0700 Subject: [PATCH 07/17] Format --- test/lifecycle_test.dart | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/lifecycle_test.dart b/test/lifecycle_test.dart index c96408a5..ff04e1b1 100644 --- a/test/lifecycle_test.dart +++ b/test/lifecycle_test.dart @@ -565,23 +565,23 @@ main() { UseStateTest = null; }); - test('useState initializes state correctly', () { - expect(countRef.text, '0'); - }); + test('useState initializes state correctly', () { + expect(countRef.text, '0'); + }); - test('useState Init initializes state correctly', () { - expect(textRef.text, 'initialValue'); - }); + test('useState Init initializes state correctly', () { + expect(textRef.text, 'initialValue'); + }); - test('StateHook.set updates state correctly', () { - react_test_utils.Simulate.click(setButtonRef); - expect(textRef.text, 'newValue'); - }); + test('StateHook.set updates state correctly', () { + react_test_utils.Simulate.click(setButtonRef); + expect(textRef.text, 'newValue'); + }); - test('StateHook.setTx updates state correctly', () { - react_test_utils.Simulate.click(setTxButtonRef); - expect(countRef.text, '1'); - }); + test('StateHook.setTx updates state correctly', () { + react_test_utils.Simulate.click(setTxButtonRef); + expect(countRef.text, '1'); + }); }); }, tags: ['functionComponent']); }); From abc3596010842a49eae5cd50ca426f52bc9c56f8 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Mon, 4 Nov 2019 11:14:29 -0700 Subject: [PATCH 08/17] Move useState to hooks.dart file --- example/test/function_component_test.dart | 3 +- lib/hooks.dart | 93 +++++++++++++++++++++++ lib/react.dart | 2 +- lib/react_client/react_interop.dart | 82 -------------------- test/lifecycle_test.dart | 5 +- 5 files changed, 99 insertions(+), 86 deletions(-) create mode 100644 lib/hooks.dart diff --git a/example/test/function_component_test.dart b/example/test/function_component_test.dart index c3fb2598..5410ec40 100644 --- a/example/test/function_component_test.dart +++ b/example/test/function_component_test.dart @@ -1,5 +1,6 @@ import 'dart:html'; +import 'package:react/hooks.dart'; import 'package:react/react.dart' as react; import 'package:react/react_dom.dart' as react_dom; import 'package:react/react_client.dart'; @@ -7,7 +8,7 @@ import 'package:react/react_client.dart'; var useStateTestFunctionComponent = react.registerFunctionComponent(UseStateTestComponent, displayName: 'useStateTest'); UseStateTestComponent(Map props) { - final count = react.useState(0); + final count = useState(0); return react.div({}, [ count.value, diff --git a/lib/hooks.dart b/lib/hooks.dart new file mode 100644 index 00000000..17cea87b --- /dev/null +++ b/lib/hooks.dart @@ -0,0 +1,93 @@ +@JS() +library hooks; + +import 'package:js/js.dart'; +import 'package:react/react.dart'; + +@JS() +abstract class React { + external static List useState(dynamic value); + external static void useEffect(void Function() effect); +} + +/// The return value of [useState]. +/// +/// The current value of the state is available via [value] and +/// functions to update it are available via [set] and [setTx]. +/// +/// Learn more: . +class StateHook { + /// The first item of the pair returned by [React.useState]. + T _value; + + /// The second item in the pair returned by [React.useState]. + void Function(dynamic) _setValue; + + StateHook(T initialValue) { + final result = React.useState(initialValue); + _value = result[0]; + _setValue = result[1]; + } + + StateHook.init(T init()) { + final result = React.useState(allowInterop(init)); + _value = result[0]; + _setValue = result[1]; + } + + /// The current value of the state. + /// + /// See: . + T get value => _value; + + /// Updates [value] to [newValue]. + /// + /// See: . + void set(T newValue) => _setValue(newValue); + + /// Updates [value] to the return value of [computeNewValue]. + /// + /// See: . + void setTx(T computeNewValue(T oldValue)) => _setValue(allowInterop(computeNewValue)); +} + +/// When called inside a [DartFunctionComponent], adds a local state to the component. +/// +/// Returns a [StateHook] with [StateHook.value] initialized to [initialValue]. +/// +/// __Example__: +/// +/// UseStateTestComponent(Map props) { +/// final count = react.useState(0); +/// +/// return react.div({}, [ +/// count.value, +/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), +/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), +/// ]); +/// } +/// +/// Learn more: . +StateHook useState(T initialValue) => new StateHook(initialValue); + +/// When called inside a [DartFunctionComponent], adds a local state to the component. +/// +/// Returns a [StateHook] with [StateHook.value] initialized to the return value of [init]. +/// +/// __Example__: +/// +/// UseStateTestComponent(Map props) { +/// final count = react.useStateInit(() { +/// var initialState = someExpensiveComputation(props); +/// return initialState; +/// })); +/// +/// return react.div({}, [ +/// count.value, +/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), +/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), +/// ]); +/// } +/// +/// Learn more: . +StateHook useStateInit(T init()) => new StateHook.init(init); diff --git a/lib/react.dart b/lib/react.dart index 80188b49..7c68baaa 100644 --- a/lib/react.dart +++ b/lib/react.dart @@ -15,7 +15,7 @@ import 'package:react/react_client/react_interop.dart'; import 'package:react/src/context.dart'; export 'package:react/src/context.dart'; -export 'package:react/react_client/react_interop.dart' show forwardRef, createRef, useState, useStateInit; +export 'package:react/react_client/react_interop.dart' show forwardRef, createRef; typedef Error PropValidator( TProps props, String propName, String componentName, String location, String propFullName); diff --git a/lib/react_client/react_interop.dart b/lib/react_client/react_interop.dart index ade41d88..146556b9 100644 --- a/lib/react_client/react_interop.dart +++ b/lib/react_client/react_interop.dart @@ -117,88 +117,6 @@ ReactJsComponentFactoryProxy forwardRef(Function(Map props, Ref ref) wrapperFunc return new ReactJsComponentFactoryProxy(hoc, shouldConvertDomProps: false); } -/// The return value of [useState]. -/// -/// The current value of the state is available via [value] and -/// functions to update it are available via [set] and [setTx]. -/// -/// Learn more: . -class StateHook { - /// The first item of the pair returned by [React.useState]. - T _value; - - /// The second item in the pair returned by [React.useState]. - void Function(dynamic) _setValue; - - StateHook(T initialValue) { - final result = React.useState(initialValue); - _value = result[0]; - _setValue = result[1]; - } - - StateHook.init(T init()) { - final result = React.useState(allowInterop(init)); - _value = result[0]; - _setValue = result[1]; - } - - /// The current value of the state. - /// - /// See: . - T get value => _value; - - /// Updates [value] to [newValue]. - /// - /// See: . - void set(T newValue) => _setValue(newValue); - - /// Updates [value] to the return value of [computeNewValue]. - /// - /// See: . - void setTx(T computeNewValue(T oldValue)) => _setValue(allowInterop(computeNewValue)); -} - -/// When called inside a [DartFunctionComponent], adds a local state to the component. -/// -/// Returns a [StateHook] with [StateHook.value] initialized to [initialValue]. -/// -/// __Example__: -/// -/// UseStateTestComponent(Map props) { -/// final count = react.useState(0); -/// -/// return react.div({}, [ -/// count.value, -/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), -/// ]); -/// } -/// -/// Learn more: . -StateHook useState(T initialValue) => new StateHook(initialValue); - -/// When called inside a [DartFunctionComponent], adds a local state to the component. -/// -/// Returns a [StateHook] with [StateHook.value] initialized to the return value of [init]. -/// -/// __Example__: -/// -/// UseStateTestComponent(Map props) { -/// final count = react.useStateInit(() { -/// var initialState = someExpensiveComputation(props); -/// return initialState; -/// })); -/// -/// return react.div({}, [ -/// count.value, -/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), -/// ]); -/// } -/// -/// Learn more: . -StateHook useStateInit(T init()) => new StateHook.init(init); - abstract class ReactDom { static Element findDOMNode(object) => ReactDOM.findDOMNode(object); static ReactComponent render(ReactElement component, Element element) => ReactDOM.render(component, element); diff --git a/test/lifecycle_test.dart b/test/lifecycle_test.dart index ff04e1b1..d82a24a7 100644 --- a/test/lifecycle_test.dart +++ b/test/lifecycle_test.dart @@ -10,6 +10,7 @@ import 'dart:js'; import "package:js/js.dart"; import 'package:meta/meta.dart'; +import 'package:react/hooks.dart'; import 'package:react/react.dart' as react; import 'package:react/react_client.dart'; import 'package:react/react_client/js_backed_map.dart'; @@ -519,10 +520,10 @@ main() { setUpAll(() { UseStateTest = react.registerFunctionComponent((Map props) { - final text = react.useStateInit(() { + final text = useStateInit(() { return 'initialValue'; }); - final count = react.useState(0); + final count = useState(0); return react.div({}, [ react.div({ From f073b95dd3af0084f59b69fdcd9d76b7d7fe34fe Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Mon, 4 Nov 2019 11:17:29 -0700 Subject: [PATCH 09/17] Move useState to hooks.dart file --- lib/hooks.dart | 1 - lib/react_client/react_interop.dart | 2 -- 2 files changed, 3 deletions(-) diff --git a/lib/hooks.dart b/lib/hooks.dart index 17cea87b..3cda2d01 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -7,7 +7,6 @@ import 'package:react/react.dart'; @JS() abstract class React { external static List useState(dynamic value); - external static void useEffect(void Function() effect); } /// The return value of [useState]. diff --git a/lib/react_client/react_interop.dart b/lib/react_client/react_interop.dart index 146556b9..22da342e 100644 --- a/lib/react_client/react_interop.dart +++ b/lib/react_client/react_interop.dart @@ -42,8 +42,6 @@ abstract class React { external static JsRef createRef(); external static ReactClass forwardRef(Function(JsMap props, JsRef ref) wrapperFunction); - - external static List useState(dynamic value); } /// Creates a [Ref] object that can be attached to a [ReactElement] via the ref prop. From 031811514ec7152db99020c6fcc05ba4b0190b79 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Mon, 4 Nov 2019 14:30:09 -0700 Subject: [PATCH 10/17] Move hooks tests to new file --- test/hooks_test.dart | 96 ++++++++++++++++++++++++++++++++++++++++ test/hooks_test.html | 15 +++++++ test/lifecycle_test.dart | 75 ------------------------------- 3 files changed, 111 insertions(+), 75 deletions(-) create mode 100644 test/hooks_test.dart create mode 100644 test/hooks_test.html diff --git a/test/hooks_test.dart b/test/hooks_test.dart new file mode 100644 index 00000000..95838323 --- /dev/null +++ b/test/hooks_test.dart @@ -0,0 +1,96 @@ +// ignore_for_file: deprecated_member_use_from_same_package +@TestOn('browser') +@JS() +library hooks_test; + +import 'dart:html'; + +import "package:js/js.dart"; +import 'package:react/hooks.dart'; +import 'package:react/react.dart' as react; +import 'package:react/react_client.dart'; +import 'package:react/react_dom.dart' as react_dom; +import 'package:react/react_test_utils.dart' as react_test_utils; +import 'package:test/test.dart'; + +main() { + setClientConfiguration(); + + group('React Hooks: ', () { + group('useState -', () { + ReactDartFunctionComponentFactoryProxy UseStateTest; + DivElement textRef; + DivElement countRef; + ButtonElement setButtonRef; + ButtonElement setTxButtonRef; + + setUpAll(() { + var mountNode = new DivElement(); + + UseStateTest = react.registerFunctionComponent((Map props) { + final text = useStateInit(() { + return 'initialValue'; + }); + final count = useState(0); + + return react.div({}, [ + react.div({ + 'ref': (ref) { + textRef = ref; + }, + }, [ + text.value + ]), + react.div({ + 'ref': (ref) { + countRef = ref; + }, + }, [ + count.value + ]), + react.button({ + 'onClick': (_) => text.set('newValue'), + 'ref': (ref) { + setButtonRef = ref; + }, + }, [ + 'Set' + ]), + react.button({ + 'onClick': (_) => count.setTx((prev) => prev + 1), + 'ref': (ref) { + setTxButtonRef = ref; + }, + }, [ + '+' + ]), + ]); + }); + + react_dom.render(UseStateTest({}), mountNode); + }); + + tearDownAll(() { + UseStateTest = null; + }); + + test('initializes state correctly', () { + expect(countRef.text, '0'); + }); + + test('Init initializes state correctly', () { + expect(textRef.text, 'initialValue'); + }); + + test('StateHook.set updates state correctly', () { + react_test_utils.Simulate.click(setButtonRef); + expect(textRef.text, 'newValue'); + }); + + test('StateHook.setTx updates state correctly', () { + react_test_utils.Simulate.click(setTxButtonRef); + expect(countRef.text, '1'); + }); + }); + }); +} diff --git a/test/hooks_test.html b/test/hooks_test.html new file mode 100644 index 00000000..556871e9 --- /dev/null +++ b/test/hooks_test.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/test/lifecycle_test.dart b/test/lifecycle_test.dart index d82a24a7..e2002a96 100644 --- a/test/lifecycle_test.dart +++ b/test/lifecycle_test.dart @@ -10,7 +10,6 @@ import 'dart:js'; import "package:js/js.dart"; import 'package:meta/meta.dart'; -import 'package:react/hooks.dart'; import 'package:react/react.dart' as react; import 'package:react/react_client.dart'; import 'package:react/react_client/js_backed_map.dart'; @@ -510,80 +509,6 @@ main() { sharedTypeTests(testTypeValue); }); - - group('- Hook useState:', () { - ReactDartFunctionComponentFactoryProxy UseStateTest; - DivElement textRef; - DivElement countRef; - ButtonElement setButtonRef; - ButtonElement setTxButtonRef; - - setUpAll(() { - UseStateTest = react.registerFunctionComponent((Map props) { - final text = useStateInit(() { - return 'initialValue'; - }); - final count = useState(0); - - return react.div({}, [ - react.div({ - 'ref': (ref) { - textRef = ref; - }, - }, [ - text.value - ]), - react.div({ - 'ref': (ref) { - countRef = ref; - }, - }, [ - count.value - ]), - react.button({ - 'onClick': (_) => text.set('newValue'), - 'ref': (ref) { - setButtonRef = ref; - }, - }, [ - 'Set' - ]), - react.button({ - 'onClick': (_) => count.setTx((prev) => prev + 1), - 'ref': (ref) { - setTxButtonRef = ref; - }, - }, [ - '+' - ]), - ]); - }); - - react_dom.render(UseStateTest({}, []), mountNode); - }); - - tearDownAll(() { - UseStateTest = null; - }); - - test('useState initializes state correctly', () { - expect(countRef.text, '0'); - }); - - test('useState Init initializes state correctly', () { - expect(textRef.text, 'initialValue'); - }); - - test('StateHook.set updates state correctly', () { - react_test_utils.Simulate.click(setButtonRef); - expect(textRef.text, 'newValue'); - }); - - test('StateHook.setTx updates state correctly', () { - react_test_utils.Simulate.click(setTxButtonRef); - expect(countRef.text, '1'); - }); - }); }, tags: ['functionComponent']); }); } From e0a36a2d5f010fe26930e239a6e948775226d529 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Mon, 4 Nov 2019 15:06:33 -0700 Subject: [PATCH 11/17] Update doc comment --- lib/hooks.dart | 5 +++++ test/hooks_test.html | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/hooks.dart b/lib/hooks.dart index 3cda2d01..8811f50f 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -14,6 +14,11 @@ abstract class React { /// The current value of the state is available via [value] and /// functions to update it are available via [set] and [setTx]. /// +/// Note are two rules for using Hooks (): +/// +/// * Only call Hooks at the top level. +/// * Only call Hooks from inside a [DartFunctionComponent]. +/// /// Learn more: . class StateHook { /// The first item of the pair returned by [React.useState]. diff --git a/test/hooks_test.html b/test/hooks_test.html index 556871e9..92a90257 100644 --- a/test/hooks_test.html +++ b/test/hooks_test.html @@ -5,8 +5,6 @@ - - From eeb5c70c298387cd1071a59b56c9935be55ec76a Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 6 Nov 2019 08:58:54 -0700 Subject: [PATCH 12/17] Add backticks for examples --- lib/hooks.dart | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/hooks.dart b/lib/hooks.dart index 8811f50f..00b7f553 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -61,15 +61,17 @@ class StateHook { /// /// __Example__: /// -/// UseStateTestComponent(Map props) { -/// final count = react.useState(0); +/// ``` +/// UseStateTestComponent(Map props) { +/// final count = react.useState(0); /// -/// return react.div({}, [ -/// count.value, -/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), -/// ]); -/// } +/// return react.div({}, [ +/// count.value, +/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), +/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), +/// ]); +/// } +/// ``` /// /// Learn more: . StateHook useState(T initialValue) => new StateHook(initialValue); @@ -80,18 +82,20 @@ StateHook useState(T initialValue) => new StateHook(initialValue); /// /// __Example__: /// -/// UseStateTestComponent(Map props) { -/// final count = react.useStateInit(() { -/// var initialState = someExpensiveComputation(props); -/// return initialState; -/// })); +/// ``` +/// UseStateTestComponent(Map props) { +/// final count = react.useStateInit(() { +/// var initialState = someExpensiveComputation(props); +/// return initialState; +/// })); /// -/// return react.div({}, [ -/// count.value, -/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), -/// ]); -/// } +/// return react.div({}, [ +/// count.value, +/// react.button({'onClick': (_) => count.set(0)}, ['Reset']), +/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), +/// ]); +/// } +/// ``` /// /// Learn more: . StateHook useStateInit(T init()) => new StateHook.init(init); From 8bcef068bfbbdba5861b1fa2cf4f0327f1fd1317 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Wed, 6 Nov 2019 10:55:10 -0700 Subject: [PATCH 13/17] Update based on reviewer feedback --- lib/hooks.dart | 30 ++++++++++++++--------------- lib/react_client/react_interop.dart | 2 ++ test/hooks_test.dart | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/hooks.dart b/lib/hooks.dart index 00b7f553..421830d2 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -3,11 +3,7 @@ library hooks; import 'package:js/js.dart'; import 'package:react/react.dart'; - -@JS() -abstract class React { - external static List useState(dynamic value); -} +import 'package:react/react_client/react_interop.dart'; /// The return value of [useState]. /// @@ -33,7 +29,11 @@ class StateHook { _setValue = result[1]; } - StateHook.init(T init()) { + /// Constructor for [useStateLazy], calls lazy version of [React.useState] to + /// initialize [_value] to the return value of [init]. + /// + /// See: . + StateHook.lazy(T init()) { final result = React.useState(allowInterop(init)); _value = result[0]; _setValue = result[1]; @@ -55,15 +55,16 @@ class StateHook { void setTx(T computeNewValue(T oldValue)) => _setValue(allowInterop(computeNewValue)); } -/// When called inside a [DartFunctionComponent], adds a local state to the component. +/// Adds local state to a [DartFunctionComponent] +/// by returning a [StateHook] with [StateHook.value] initialized to [initialValue]. /// -/// Returns a [StateHook] with [StateHook.value] initialized to [initialValue]. +/// > __Note:__ If the [initialValue] is expensive to compute, [useStateLazy] should be used instead. /// /// __Example__: /// /// ``` /// UseStateTestComponent(Map props) { -/// final count = react.useState(0); +/// final count = useState(0); /// /// return react.div({}, [ /// count.value, @@ -74,17 +75,16 @@ class StateHook { /// ``` /// /// Learn more: . -StateHook useState(T initialValue) => new StateHook(initialValue); +StateHook useState(T initialValue) => StateHook(initialValue); -/// When called inside a [DartFunctionComponent], adds a local state to the component. -/// -/// Returns a [StateHook] with [StateHook.value] initialized to the return value of [init]. +/// Adds local state to a [DartFunctionComponent] +/// by returning a [StateHook] with [StateHook.value] initialized to the return value of [init]. /// /// __Example__: /// /// ``` /// UseStateTestComponent(Map props) { -/// final count = react.useStateInit(() { +/// final count = useStateLazy(() { /// var initialState = someExpensiveComputation(props); /// return initialState; /// })); @@ -98,4 +98,4 @@ StateHook useState(T initialValue) => new StateHook(initialValue); /// ``` /// /// Learn more: . -StateHook useStateInit(T init()) => new StateHook.init(init); +StateHook useStateLazy(T init()) => StateHook.lazy(init); diff --git a/lib/react_client/react_interop.dart b/lib/react_client/react_interop.dart index 22da342e..146556b9 100644 --- a/lib/react_client/react_interop.dart +++ b/lib/react_client/react_interop.dart @@ -42,6 +42,8 @@ abstract class React { external static JsRef createRef(); external static ReactClass forwardRef(Function(JsMap props, JsRef ref) wrapperFunction); + + external static List useState(dynamic value); } /// Creates a [Ref] object that can be attached to a [ReactElement] via the ref prop. diff --git a/test/hooks_test.dart b/test/hooks_test.dart index 95838323..8e98e083 100644 --- a/test/hooks_test.dart +++ b/test/hooks_test.dart @@ -28,7 +28,7 @@ main() { var mountNode = new DivElement(); UseStateTest = react.registerFunctionComponent((Map props) { - final text = useStateInit(() { + final text = useStateLazy(() { return 'initialValue'; }); final count = useState(0); From 0dd585d4f89f080993febb295bb51302223d42b0 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Mon, 11 Nov 2019 09:09:38 -0700 Subject: [PATCH 14/17] Update `setTx` to `setWithUpdater` --- example/test/function_component_test.dart | 2 +- lib/hooks.dart | 8 ++++---- test/hooks_test.dart | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/example/test/function_component_test.dart b/example/test/function_component_test.dart index 5410ec40..95694d16 100644 --- a/example/test/function_component_test.dart +++ b/example/test/function_component_test.dart @@ -13,7 +13,7 @@ UseStateTestComponent(Map props) { return react.div({}, [ count.value, react.button({'onClick': (_) => count.set(0)}, ['Reset']), - react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), + react.button({'onClick': (_) => count.setWithUpdater((prev) => prev + 1)}, ['+']), ]); } diff --git a/lib/hooks.dart b/lib/hooks.dart index 421830d2..203b3a71 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -8,7 +8,7 @@ import 'package:react/react_client/react_interop.dart'; /// The return value of [useState]. /// /// The current value of the state is available via [value] and -/// functions to update it are available via [set] and [setTx]. +/// functions to update it are available via [set] and [setWithUpdater]. /// /// Note are two rules for using Hooks (): /// @@ -52,7 +52,7 @@ class StateHook { /// Updates [value] to the return value of [computeNewValue]. /// /// See: . - void setTx(T computeNewValue(T oldValue)) => _setValue(allowInterop(computeNewValue)); + void setWithUpdater(T computeNewValue(T oldValue)) => _setValue(allowInterop(computeNewValue)); } /// Adds local state to a [DartFunctionComponent] @@ -69,7 +69,7 @@ class StateHook { /// return react.div({}, [ /// count.value, /// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), +/// react.button({'onClick': (_) => count.setWithUpdater((prev) => prev + 1)}, ['+']), /// ]); /// } /// ``` @@ -92,7 +92,7 @@ StateHook useState(T initialValue) => StateHook(initialValue); /// return react.div({}, [ /// count.value, /// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.setTx((prev) => prev + 1)}, ['+']), +/// react.button({'onClick': (_) => count.setWithUpdater((prev) => prev + 1)}, ['+']), /// ]); /// } /// ``` diff --git a/test/hooks_test.dart b/test/hooks_test.dart index 8e98e083..e80492df 100644 --- a/test/hooks_test.dart +++ b/test/hooks_test.dart @@ -22,7 +22,7 @@ main() { DivElement textRef; DivElement countRef; ButtonElement setButtonRef; - ButtonElement setTxButtonRef; + ButtonElement setWithUpdaterButtonRef; setUpAll(() { var mountNode = new DivElement(); @@ -57,9 +57,9 @@ main() { 'Set' ]), react.button({ - 'onClick': (_) => count.setTx((prev) => prev + 1), + 'onClick': (_) => count.setWithUpdater((prev) => prev + 1), 'ref': (ref) { - setTxButtonRef = ref; + setWithUpdaterButtonRef = ref; }, }, [ '+' @@ -78,7 +78,7 @@ main() { expect(countRef.text, '0'); }); - test('Init initializes state correctly', () { + test('Lazy initializes state correctly', () { expect(textRef.text, 'initialValue'); }); @@ -87,8 +87,8 @@ main() { expect(textRef.text, 'newValue'); }); - test('StateHook.setTx updates state correctly', () { - react_test_utils.Simulate.click(setTxButtonRef); + test('StateHook.setWithUpdater updates state correctly', () { + react_test_utils.Simulate.click(setWithUpdaterButtonRef); expect(countRef.text, '1'); }); }); From 37d9629aaf1897aded271aedd0a5a3159ad3c0d0 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Mon, 11 Nov 2019 09:44:52 -0700 Subject: [PATCH 15/17] Update doc comment --- lib/hooks.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hooks.dart b/lib/hooks.dart index 203b3a71..ed058b92 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -10,7 +10,7 @@ import 'package:react/react_client/react_interop.dart'; /// The current value of the state is available via [value] and /// functions to update it are available via [set] and [setWithUpdater]. /// -/// Note are two rules for using Hooks (): +/// Note there are two rules for using Hooks (): /// /// * Only call Hooks at the top level. /// * Only call Hooks from inside a [DartFunctionComponent]. From d8da3d7fe0db517e0c92cf1f89afb9d4e5ad7422 Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Mon, 11 Nov 2019 10:27:27 -0700 Subject: [PATCH 16/17] Add better `setWithUpdater` example --- example/test/function_component_test.dart | 24 +++++++++++++++++++++-- lib/hooks.dart | 12 ++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/example/test/function_component_test.dart b/example/test/function_component_test.dart index 95694d16..e7b0cb19 100644 --- a/example/test/function_component_test.dart +++ b/example/test/function_component_test.dart @@ -13,7 +13,17 @@ UseStateTestComponent(Map props) { return react.div({}, [ count.value, react.button({'onClick': (_) => count.set(0)}, ['Reset']), - react.button({'onClick': (_) => count.setWithUpdater((prev) => prev + 1)}, ['+']), + react.button({ + 'onClick': (_) => count.setWithUpdater((prev) { + if (props['enabled']) { + return prev + 1; + } else { + return prev; + } + }), + }, [ + '+' + ]), ]); } @@ -23,8 +33,18 @@ void main() { render() { react_dom.render( react.Fragment({}, [ + react.h1({'key': 'functionComponentTestLabel'}, ['Function Component Tests']), react.h2({'key': 'useStateTestLabel'}, ['useState Hook Test']), - useStateTestFunctionComponent({'key': 'useStateTest'}, []) + useStateTestFunctionComponent({ + 'key': 'useStateTest', + 'enabled': true, + }, []), + react.br({}), + react.h5({'key': 'useStateTestLabel-2'}, 'Disabled:'), + useStateTestFunctionComponent({ + 'key': 'useStateTest', + 'enabled': false, + }, []), ]), querySelector('#content')); } diff --git a/lib/hooks.dart b/lib/hooks.dart index ed058b92..b94079b9 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -69,7 +69,15 @@ class StateHook { /// return react.div({}, [ /// count.value, /// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.setWithUpdater((prev) => prev + 1)}, ['+']), +/// react.button({ +/// 'onClick': (_) => count.setWithUpdater((prev) { +/// if (props['enabled']) { +/// return prev + 1; +/// } else { +/// return prev; +/// } +/// }), +/// }, ['+']), /// ]); /// } /// ``` @@ -92,7 +100,7 @@ StateHook useState(T initialValue) => StateHook(initialValue); /// return react.div({}, [ /// count.value, /// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.setWithUpdater((prev) => prev + 1)}, ['+']), +/// react.button({'onClick': (_) => count.set(count.value + 1)}, ['+']), /// ]); /// } /// ``` From 5aa03e7cdf840f4a43ed5629ff07b5e13cc6780c Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Mon, 18 Nov 2019 12:51:34 -0700 Subject: [PATCH 17/17] Update based on Greg's feedback --- example/test/function_component_test.dart | 15 +-------------- lib/hooks.dart | 10 ++-------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/example/test/function_component_test.dart b/example/test/function_component_test.dart index e7b0cb19..2218618b 100644 --- a/example/test/function_component_test.dart +++ b/example/test/function_component_test.dart @@ -14,13 +14,7 @@ UseStateTestComponent(Map props) { count.value, react.button({'onClick': (_) => count.set(0)}, ['Reset']), react.button({ - 'onClick': (_) => count.setWithUpdater((prev) { - if (props['enabled']) { - return prev + 1; - } else { - return prev; - } - }), + 'onClick': (_) => count.setWithUpdater((prev) => prev + 1), }, [ '+' ]), @@ -37,13 +31,6 @@ void main() { react.h2({'key': 'useStateTestLabel'}, ['useState Hook Test']), useStateTestFunctionComponent({ 'key': 'useStateTest', - 'enabled': true, - }, []), - react.br({}), - react.h5({'key': 'useStateTestLabel-2'}, 'Disabled:'), - useStateTestFunctionComponent({ - 'key': 'useStateTest', - 'enabled': false, }, []), ]), querySelector('#content')); diff --git a/lib/hooks.dart b/lib/hooks.dart index b94079b9..484de6bb 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -70,13 +70,7 @@ class StateHook { /// count.value, /// react.button({'onClick': (_) => count.set(0)}, ['Reset']), /// react.button({ -/// 'onClick': (_) => count.setWithUpdater((prev) { -/// if (props['enabled']) { -/// return prev + 1; -/// } else { -/// return prev; -/// } -/// }), +/// 'onClick': (_) => count.setWithUpdater((prev) => prev + 1), /// }, ['+']), /// ]); /// } @@ -100,7 +94,7 @@ StateHook useState(T initialValue) => StateHook(initialValue); /// return react.div({}, [ /// count.value, /// react.button({'onClick': (_) => count.set(0)}, ['Reset']), -/// react.button({'onClick': (_) => count.set(count.value + 1)}, ['+']), +/// react.button({'onClick': (_) => count.set((prev) => prev + 1)}, ['+']), /// ]); /// } /// ```