diff --git a/.github/workflows/dart_ci.yml b/.github/workflows/dart_ci.yml index 34c7a9b2..f5ab2439 100644 --- a/.github/workflows/dart_ci.yml +++ b/.github/workflows/dart_ci.yml @@ -15,8 +15,8 @@ jobs: strategy: fail-fast: false matrix: - # Can't run on `beta` (Dart 3) until we're fully null-safe. - sdk: [2.18.7, stable] + # Can't run on `stable` (Dart 3) until we're fully null-safe. + sdk: [2.18.7] steps: - uses: actions/checkout@v2 - uses: dart-lang/setup-dart@v1 diff --git a/analysis_options.yaml b/analysis_options.yaml index 6da2c16d..ed7c50a6 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,12 +1,25 @@ +include: package:workiva_analysis_options/v2.recommended.yaml + analyzer: strong-mode: + # TODO change to false as part of the null safety major, which avoids us having to add a lot more casts implicit-casts: true - implicit-dynamic: true + errors: + must_call_super: error + comment_references: info + # This is too noisy since it warns for all lifecycle methods. + always_declare_return_types: ignore + # We very often need to annotate parameters when they're embedded in Maps + # with dynamic values, so this lint is noisy and wrong in those cases. + # See: https://github.com/dart-lang/linter/issues/1099 + avoid_types_on_closure_parameters: ignore + # This makes string concatenation less readable in some cases + prefer_interpolation_to_compose_strings: ignore + # The following are ignored to avoid merge conflicts with null safety branch + directives_ordering: ignore + prefer_typing_uninitialized_variables: ignore linter: rules: - - avoid_private_typedef_functions - - await_only_futures - - cancel_subscriptions - - close_sinks - - unawaited_futures - - avoid_init_to_null + prefer_if_elements_to_conditional_expressions: false + overridden_fields: false + type_annotate_public_apis: false diff --git a/example/geocodes/geocodes.dart b/example/geocodes/geocodes.dart index c035e485..4596dd71 100644 --- a/example/geocodes/geocodes.dart +++ b/example/geocodes/geocodes.dart @@ -6,32 +6,30 @@ import 'dart:html'; import 'package:react/react.dart' as react; import 'package:react/react_dom.dart' as react_dom; -/** - * Hello, - * - * This is the Dart portion of the tutorial for the Dart react package. - * - * We'll go through a simple app that queries the Google Maps API and shows the result to the user. - * It also stores the search history and allows the user to reload past queries. - * - * In this file you'll find the structure and the logic of the app. There is also a `geocodes.html` file which contains - * the mount point. - * - * Be sure that you understand the basic concepts of [React](http://facebook.github.io/react/) before reading this - * tutorial. - * - * Enjoy! - */ +/// Hello, +/// +/// This is the Dart portion of the tutorial for the Dart react package. +/// +/// We'll go through a simple app that queries the Google Maps API and shows the result to the user. +/// It also stores the search history and allows the user to reload past queries. +/// +/// In this file you'll find the structure and the logic of the app. There is also a `geocodes.html` file which contains +/// the mount point. +/// +/// Be sure that you understand the basic concepts of [React](https://reactjs.org/) before reading this +/// tutorial. +/// +/// Enjoy! /// Divide your app into components and conquer! /// -/// This is the first custom [Component]. +/// This is the first custom `Component`. /// /// It is just an HTML `` element displaying a single API response to the user. class _GeocodesResultItem extends react.Component { /// The only function you must implement in the custom component is [render]. /// - /// Every [Component] has a map of properties called [Component.props]. It can be specified during creation. + /// Every `Component` has a map of properties called `props`. It can be specified during creation. @override render() { return react.tr({}, [ @@ -42,13 +40,13 @@ class _GeocodesResultItem extends react.Component { } } -/// Now we need to tell ReactJS that our custom [Component] exists by calling [registerComponent]. +/// Now we need to tell ReactJS that our custom `Component` exists by calling `registerComponent`. /// /// As a reward, it gives us a function, that takes the properties and returns our element. You'll see it in action /// shortly. /// -/// This is the only correct way to create a [Component]. Do not use the constructor! -var geocodesResultItem = react.registerComponent(() => new _GeocodesResultItem()); +/// This is the only correct way to create a `Component`. Do not use the constructor! +var geocodesResultItem = react.registerComponent(() => _GeocodesResultItem()); /// In this component we'll build an HTML `` element full of the `` elements generated by /// [_GeocodesResultItem] @@ -95,13 +93,13 @@ class _GeocodesResultList extends react.Component { } } -var geocodesResultList = react.registerComponent(() => new _GeocodesResultList()); +var geocodesResultList = react.registerComponent(() => _GeocodesResultList()); -/// In this [Component] we'll build a search form. +/// In this `Component` we'll build a search form. /// -/// This [Component] illustrates that: +/// This `Component` illustrates that: /// -/// > The functions can be [Component] parameters _(handy for callbacks)_ +/// > The functions can be `Component` parameters _(handy for callbacks)_ /// /// > The DOM [Element]s can be accessed using `ref`s. class _GeocodesForm extends react.Component { @@ -158,16 +156,16 @@ class _GeocodesForm extends react.Component { /// Handle form submission via `props.onSubmit` onFormSubmit(react.SyntheticEvent event) { event.preventDefault(); - InputElement inputElement = react_dom.findDOMNode(searchInputInstance); + final inputElement = react_dom.findDOMNode(searchInputInstance); // The input's value is accessed. - var address = inputElement.value; + final address = inputElement.value; inputElement.value = ''; // Call the callback from the parent element is called. props['submitter'](address); } } -var geocodesForm = react.registerComponent(() => new _GeocodesForm()); +var geocodesForm = react.registerComponent(() => _GeocodesForm()); /// Renders an HTML `
  • ` to be used as a child within the [_GeocodesHistoryList]. class _GeocodesHistoryItem extends react.Component { @@ -189,7 +187,7 @@ class _GeocodesHistoryItem extends react.Component { } } -var geocodesHistoryItem = react.registerComponent(() => new _GeocodesHistoryItem()); +var geocodesHistoryItem = react.registerComponent(() => _GeocodesHistoryItem()); /// Renders the "history list" /// @@ -203,7 +201,7 @@ class _GeocodesHistoryList extends react.Component { { 'key': 'list', }, - new List.from(props['data'].keys.map((key) => geocodesHistoryItem({ + List.from((props['data'] as Map).keys.map((key) => geocodesHistoryItem({ 'key': key, 'query': props['data'][key]['query'], 'status': props['data'][key]['status'], @@ -214,11 +212,11 @@ class _GeocodesHistoryList extends react.Component { } } -var geocodesHistoryList = react.registerComponent(() => new _GeocodesHistoryList()); +var geocodesHistoryList = react.registerComponent(() => _GeocodesHistoryList()); -/// The root [Component] of our application. +/// The root `Component` of our application. /// -/// Introduces [state]. Both [state] and [props] are valid locations to store [Component] data. +/// Introduces [state]. Both [state] and [props] are valid locations to store `Component` data. /// /// However, there are some key differences to note: /// @@ -228,7 +226,7 @@ var geocodesHistoryList = react.registerComponent(() => new _GeocodesHistoryList /// /// > When [state] is changed, the component will re-render. /// -/// It's a common practice to store the application data in the [state] of the root [Component]. It will re-render +/// It's a common practice to store the application data in the [state] of the root `Component`. It will re-render /// every time the state is changed. However, it is not required - you can also use normal variables and re-render /// manually if you wish. /// @@ -247,23 +245,23 @@ class _GeocodesApp extends react.Component { /// Sends the [addressQuery] to the API and processes the result newQuery(String addressQuery) async { // Once the query is being sent, it appears in the history and is given an id. - var id = addQueryToHistory(addressQuery); + final id = addQueryToHistory(addressQuery); // Prepare the URL addressQuery = Uri.encodeQueryComponent(addressQuery); - var path = 'https://maps.googleapis.com/maps/api/geocode/json?address=$addressQuery'; + final path = 'https://maps.googleapis.com/maps/api/geocode/json?address=$addressQuery'; try { // Send the request - var raw = await HttpRequest.getString(path); + final raw = await HttpRequest.getString(path); // Delay the answer 2 more seconds, for test purposes - await new Future.delayed(new Duration(seconds: 2)); + await Future.delayed(Duration(seconds: 2)); // Is this the answer to the last request? if (id == last_id) { // If yes, query was `OK` and `shown_addresses` are replaced state['history'][id]['status'] = 'OK'; - var data = json.decode(raw); + final data = json.decode(raw); // Calling `setState` will update the state and then repaint the component. // @@ -291,7 +289,7 @@ class _GeocodesApp extends react.Component { /// Add a new [addressQuery] to the `state.history` Map with its status set to 'pending', then return its `id`. addQueryToHistory(String addressQuery) { - var id = ++last_id; + final id = ++last_id; state['history'][id] = {'query': addressQuery, 'status': 'pending'}; @@ -324,7 +322,7 @@ class _GeocodesApp extends react.Component { } } -var geocodesApp = react.registerComponent(() => new _GeocodesApp()); +var geocodesApp = react.registerComponent(() => _GeocodesApp()); /// And finally, a few magic commands to wire it all up! /// diff --git a/example/geocodes/geocodes.html b/example/geocodes/geocodes.html index 453ead1f..fef1312c 100644 --- a/example/geocodes/geocodes.html +++ b/example/geocodes/geocodes.html @@ -12,7 +12,7 @@ * In this file you'll find the mount point of the app. There is also a `geocodes.dart` file which contains the * structure and the application logic. * - * Be sure that you understand the basic concepts of [React](http://facebook.github.io/react/) before reading this + * Be sure that you understand the basic concepts of [React](https://reactjs.org/) before reading this * tutorial. * * Enjoy! diff --git a/example/js_components/js_components.dart b/example/js_components/js_components.dart index b66e760b..08132513 100644 --- a/example/js_components/js_components.dart +++ b/example/js_components/js_components.dart @@ -10,33 +10,35 @@ import 'package:react/react_client/react_interop.dart'; import 'package:react/react_dom.dart' as react_dom; main() { - var content = IndexComponent({}); + final content = IndexComponent({}); react_dom.render(content, querySelector('#content')); } -var IndexComponent = react.registerComponent2(() => new _IndexComponent()); +var IndexComponent = react.registerComponent2(() => _IndexComponent()); class _IndexComponent extends react.Component2 { SimpleCustomComponent simpleRef; + @override get initialState => { 'open': false, }; handleClose(_) { - this.setState({ + setState({ 'open': false, }); } handleClick(_) { - this.setState({ + setState({ 'open': true, }); print(simpleRef.getFoo()); } + @override render() { return MuiThemeProvider( { @@ -45,7 +47,7 @@ class _IndexComponent extends react.Component2 { SimpleCustom({ 'foo': 'Foo Prop from dart... IN A JAVASCRIPT COMPONENT!', 'ref': (ref) { - simpleRef = ref; + simpleRef = ref as SimpleCustomComponent; } }), CssBaseline({}), @@ -62,21 +64,21 @@ class _IndexComponent extends react.Component2 { DialogActions( {}, Button({ - 'color': "primary", + 'color': 'primary', 'onClick': handleClose, }, 'OK'), )), Typography({ - 'variant': "h4", + 'variant': 'h4', 'gutterBottom': true, }, 'Material-UI'), Typography({ - 'variant': "subtitle1", + 'variant': 'subtitle1', 'gutterBottom': true, }, 'example project'), Button({ - 'variant': "contained", - 'color': "secondary", + 'variant': 'contained', + 'color': 'secondary', 'onClick': handleClick, }, Icon({}, 'fingerprint'), 'Super Secret Password'), ); @@ -98,7 +100,7 @@ external ReactClass get _SimpleCustomComponent; /// /// This converts the Dart props [Map] passed into it in the /// the same way props are converted for DOM components. -final SimpleCustom = new ReactJsComponentFactoryProxy(_SimpleCustomComponent); +final SimpleCustom = ReactJsComponentFactoryProxy(_SimpleCustomComponent); /// JS interop wrapper class for the component, /// allowing us to interact with component instances @@ -131,13 +133,13 @@ class MaterialUI { external Map get theme; // All the Material UI components converted to dart Components -final Button = new ReactJsComponentFactoryProxy(MaterialUI.Button); -final CssBaseline = new ReactJsComponentFactoryProxy(MaterialUI.CssBaseline); -final Dialog = new ReactJsComponentFactoryProxy(MaterialUI.Dialog); -final DialogActions = new ReactJsComponentFactoryProxy(MaterialUI.DialogActions); -final DialogContent = new ReactJsComponentFactoryProxy(MaterialUI.DialogContent); -final DialogContentText = new ReactJsComponentFactoryProxy(MaterialUI.DialogContentText); -final DialogTitle = new ReactJsComponentFactoryProxy(MaterialUI.DialogTitle); -final Icon = new ReactJsComponentFactoryProxy(MaterialUI.Icon); -final MuiThemeProvider = new ReactJsComponentFactoryProxy(MaterialUI.MuiThemeProvider); -final Typography = new ReactJsComponentFactoryProxy(MaterialUI.Typography); +final Button = ReactJsComponentFactoryProxy(MaterialUI.Button); +final CssBaseline = ReactJsComponentFactoryProxy(MaterialUI.CssBaseline); +final Dialog = ReactJsComponentFactoryProxy(MaterialUI.Dialog); +final DialogActions = ReactJsComponentFactoryProxy(MaterialUI.DialogActions); +final DialogContent = ReactJsComponentFactoryProxy(MaterialUI.DialogContent); +final DialogContentText = ReactJsComponentFactoryProxy(MaterialUI.DialogContentText); +final DialogTitle = ReactJsComponentFactoryProxy(MaterialUI.DialogTitle); +final Icon = ReactJsComponentFactoryProxy(MaterialUI.Icon); +final MuiThemeProvider = ReactJsComponentFactoryProxy(MaterialUI.MuiThemeProvider); +final Typography = ReactJsComponentFactoryProxy(MaterialUI.Typography); diff --git a/example/suspense/suspense.dart b/example/suspense/suspense.dart index 6c8654fe..7517a647 100644 --- a/example/suspense/suspense.dart +++ b/example/suspense/suspense.dart @@ -18,7 +18,8 @@ external ReactClass jsLazy(Promise Function() factory); // Only intended for testing purposes, Please do not copy/paste this into repo. // This will most likely be added to the PUBLIC api in the future, // but needs more testing and Typing decisions to be made first. -ReactJsComponentFactoryProxy lazy(Future factory()) => ReactJsComponentFactoryProxy( +ReactJsComponentFactoryProxy lazy(Future Function() factory) => + ReactJsComponentFactoryProxy( jsLazy( allowInterop( () => futureToPromise( @@ -32,7 +33,7 @@ ReactJsComponentFactoryProxy lazy(Future factory()) ); main() { - var content = wrapper({}); + final content = wrapper({}); react_dom.render(content, querySelector('#content')); } diff --git a/example/test/call_and_nosuchmethod_test.dart b/example/test/call_and_nosuchmethod_test.dart index 0dcf43af..6c379b65 100644 --- a/example/test/call_and_nosuchmethod_test.dart +++ b/example/test/call_and_nosuchmethod_test.dart @@ -1,16 +1,17 @@ // ignore_for_file: deprecated_member_use_from_same_package -import "dart:html"; +import 'dart:html'; -import "package:react/react_dom.dart" as react_dom; -import "package:react/react.dart" as react; +import 'package:react/react_dom.dart' as react_dom; +import 'package:react/react.dart' as react; class _CustomComponent extends react.Component { + @override render() { return react.div({}, props['children']); } } -var customComponent = react.registerComponent(() => new _CustomComponent()); +var customComponent = react.registerComponent(() => _CustomComponent()); void main() { react_dom.render( diff --git a/example/test/context_test.dart b/example/test/context_test.dart index 61970e52..503ab13e 100644 --- a/example/test/context_test.dart +++ b/example/test/context_test.dart @@ -25,7 +25,7 @@ void main() { }), newContextConsumerObservedBitsComponent({ 'key': 'newConsumerObservedBitsComponent', - 'unstable_observedBits': (1 << 2), + 'unstable_observedBits': 1 << 2, }), newContextTypeConsumerComponentComponent({'key': 'newContextTypeConsumerComponent'}, []), ]), diff --git a/example/test/error_boundary_test.dart b/example/test/error_boundary_test.dart index 263a9a5b..f4e74ba5 100644 --- a/example/test/error_boundary_test.dart +++ b/example/test/error_boundary_test.dart @@ -42,19 +42,19 @@ final _ErrorBoundary = react.registerComponent2(() => _ErrorBoundaryComponent(), class _ErrorBoundaryComponent extends react.Component2 { @override - Map get initialState => {'hasError': false}; + get initialState => {'hasError': false}; @override - Map getDerivedStateFromError(dynamic error) => {'hasError': true}; + getDerivedStateFromError(dynamic error) => {'hasError': true}; @override - void componentDidCatch(dynamic error, ReactErrorInfo info) { + componentDidCatch(dynamic error, ReactErrorInfo info) { props['onComponentDidCatch']?.call(error, info); } @override render() { - return state['hasError'] ? 'Error boundary caught an error' : props['children']; + return (state['hasError'] as bool) ? 'Error boundary caught an error' : props['children']; } } @@ -62,11 +62,11 @@ final _ThrowingComponent = react.registerComponent2(() => _ThrowingComponentComp class _ThrowingComponentComponent2 extends react.Component2 { @override - Map get initialState => {'shouldThrow': false}; + get initialState => {'shouldThrow': false}; @override render() { - if (state['shouldThrow']) { + if (state['shouldThrow'] as bool) { throw Exception(); } diff --git a/example/test/false_and_null_test.dart b/example/test/false_and_null_test.dart index a73a365d..c26fe843 100644 --- a/example/test/false_and_null_test.dart +++ b/example/test/false_and_null_test.dart @@ -5,6 +5,7 @@ import 'package:react/react.dart' as react; import 'package:react/react_dom.dart' as react_dom; class _Component extends react.Component { + @override render() { if (props['hardCodedNullReturn'] == true) { return null; @@ -14,10 +15,10 @@ class _Component extends react.Component { } } -var component = react.registerComponent(() => new _Component()); +var component = react.registerComponent(() => _Component()); void main() { - var content = react.div({}, [ + final content = react.div({}, [ react.p({}, 'Testing a dynamic return value of "null"...'), component({'returnValue': null, 'key': 0}), react.p({}, 'Testing a hard-coded return value of "null"...'), diff --git a/example/test/function_component_test.dart b/example/test/function_component_test.dart index b0327b7c..1435a583 100644 --- a/example/test/function_component_test.dart +++ b/example/test/function_component_test.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:react/hooks.dart'; import 'package:react/react.dart' as react; -import 'package:react/react_client/react_interop.dart'; import 'package:react/react_dom.dart' as react_dom; var hookTestFunctionComponent = react.registerFunctionComponent(HookTestComponent, displayName: 'useStateTest'); @@ -46,29 +45,29 @@ class _MemoTestDemoWrapper extends react.Component2 { return react.div( {'key': 'mtdw'}, MemoTest({ - 'localCount': this.state['localCount'], - 'someKeyThatMemoShouldIgnore': this.state['someKeyThatMemoShouldIgnore'], + 'localCount': state['localCount'], + 'someKeyThatMemoShouldIgnore': state['someKeyThatMemoShouldIgnore'], }), react.button({ 'type': 'button', 'className': 'btn btn-primary', 'style': {'marginRight': '10px'}, 'onClick': (_) { - this.setState({'localCount': this.state['localCount'] + 1}); + setState({'localCount': state['localCount'] + 1}); }, - }, 'Update MemoTest props.localCount value (${this.state['localCount']})'), + }, 'Update MemoTest props.localCount value (${state['localCount']})'), react.button({ 'type': 'button', 'className': 'btn btn-primary', 'onClick': (_) { - this.setState({'someKeyThatMemoShouldIgnore': this.state['someKeyThatMemoShouldIgnore'] + 1}); + setState({'someKeyThatMemoShouldIgnore': state['someKeyThatMemoShouldIgnore'] + 1}); }, - }, 'Update prop value that MemoTest will ignore (${this.state['someKeyThatMemoShouldIgnore']})'), + }, 'Update prop value that MemoTest will ignore (${state['someKeyThatMemoShouldIgnore']})'), ); } } -final MemoTest = react.memo2(react.registerFunctionComponent((Map props) { +final MemoTest = react.memo2(react.registerFunctionComponent((props) { final context = useContext(TestNewContext); return react.div( {}, @@ -107,14 +106,15 @@ Map reducer(Map state, Map action) { case 'decrement': return {...state, 'count': state['count'] - 1}; case 'reset': - return initializeCount(action['payload']); + return initializeCount(action['payload'] as int); default: return state; } } UseReducerTestComponent(Map props) { - final ReducerHook state = useReducerLazy(reducer, props['initialCount'], initializeCount); + final initialCount = props['initialCount'] as int; + final state = useReducerLazy(reducer, initialCount, initializeCount); return react.Fragment({}, [ state.state['count'], @@ -134,7 +134,7 @@ UseReducerTestComponent(Map props) { 'key': 'urt3', 'onClick': (_) => state.dispatch({ 'type': 'reset', - 'payload': props['initialCount'], + 'payload': initialCount, }) }, [ 'reset' @@ -149,11 +149,11 @@ UseCallbackTestComponent(Map props) { final count = useState(0); final delta = useState(1); - var increment = useCallback((_) { + final increment = useCallback((_) { count.setWithUpdater((prev) => prev + delta.value); }, [delta.value]); - var incrementDelta = useCallback((_) { + final incrementDelta = useCallback((_) { delta.setWithUpdater((prev) => prev + 1); }, []); @@ -178,7 +178,7 @@ UseContextTestComponent(Map props) { } int calculateChangedBits(currentValue, nextValue) { - int result = 1 << 1; + var result = 1 << 1; if (nextValue['renderCount'] % 2 == 0) { result |= 1 << 2; } @@ -190,10 +190,12 @@ var TestNewContext = react.createContext({'renderCount': 0}, calculateChang var newContextProviderComponent = react.registerComponent2(() => _NewContextProviderComponent()); class _NewContextProviderComponent extends react.Component2 { + @override get initialState => {'renderCount': 0, 'complexMap': false}; + @override render() { - final provideMap = {'renderCount': this.state['renderCount']}; + final provideMap = {'renderCount': state['renderCount']}; return react.div({ 'key': 'ulasda', @@ -208,7 +210,7 @@ class _NewContextProviderComponent extends react.Component2 { 'onClick': _onButtonClick, }, 'Redraw'), react.br({'key': 'break1'}), - 'TestContext.Provider props.value: ${provideMap}', + 'TestContext.Provider props.value: $provideMap', react.br({'key': 'break2'}), react.br({'key': 'break3'}), TestNewContext.Provider( @@ -219,7 +221,7 @@ class _NewContextProviderComponent extends react.Component2 { } _onButtonClick(event) { - this.setState({'renderCount': this.state['renderCount'] + 1, 'complexMap': false}); + setState({'renderCount': state['renderCount'] + 1, 'complexMap': false}); } } @@ -283,7 +285,7 @@ UseMemoTestComponent2(Map props) { final fib = fibonacci(count.value); return react.Fragment({}, [ - react.div({'key': 'div'}, ['Fibonacci of ${count.value} is ${fib}']), + react.div({'key': 'div'}, ['Fibonacci of ${count.value} is $fib']), react.button({'key': 'button1', 'onClick': (_) => count.setWithUpdater((prev) => prev + 1)}, ['+']), react.button({'key': 'button2', 'onClick': (_) => reRender.setWithUpdater((prev) => prev + 1)}, ['re-render']), ]); @@ -295,7 +297,7 @@ final randomUseLayoutEffectTestComponent = react.registerFunctionComponent(RandomUseLayoutEffectTestComponent, displayName: 'randomUseLayoutEffectTest'); RandomUseLayoutEffectTestComponent(Map props) { - StateHook value = useState(0); + final value = useState(0); useLayoutEffect(() { if (value.value == 0) { @@ -315,7 +317,7 @@ final randomUseEffectTestComponent = react.registerFunctionComponent(RandomUseEffectTestComponent, displayName: 'randomUseEffectTest'); RandomUseEffectTestComponent(Map props) { - StateHook value = useState(0); + final value = useState(0); useEffect(() { if (value.value == 0) { @@ -355,7 +357,7 @@ final FancyInput = react.forwardRef2((props, ref) { 'value': props['value'], 'onChange': (e) => props['update'](e.target.value), 'placeholder': props['placeholder'], - 'style': {'borderColor': props['hasError'] ? 'crimson' : '#999'}, + 'style': {'borderColor': (props['hasError'] as bool) ? 'crimson' : '#999'}, }); }); @@ -368,8 +370,8 @@ UseImperativeHandleTestComponent(Map props) { final error = useState(''); final message = useState(''); - Ref cityRef = useRef(); - Ref stateRef = useRef(); + final cityRef = useRef(); + final stateRef = useRef(); validate(_) { if (!RegExp(r'^[a-zA-Z]+$').hasMatch(city.value)) { @@ -413,21 +415,23 @@ UseImperativeHandleTestComponent(Map props) { } final FancyCounter = react.forwardRef2((props, ref) { - final count = useState(0); + final diff = props['diff'] as num; + + final count = useState(0); useImperativeHandle( ref, () { print('FancyCounter: useImperativeHandle re-assigns ref.current'); return { - 'increment': () => count.setWithUpdater((prev) => prev + props['diff']), - 'decrement': () => count.setWithUpdater((prev) => prev - props['diff']), + 'increment': () => count.setWithUpdater((prev) => prev + diff), + 'decrement': () => count.setWithUpdater((prev) => prev - diff), }; }, /// This dependency prevents unnecessary calls of createHandle, by only re-assigning - /// ref.current when `props['diff']` changes. - [props['diff']], + /// ref.current when `diff` changes. + [diff], ); return react.div({}, count.value); @@ -465,7 +469,7 @@ UseImperativeHandleTestComponent2(Map props) { class ChatAPI { static void subscribeToFriendStatus(int id, Function handleStatusChange) => - handleStatusChange({'isOnline': id % 2 == 0 ? true : false}); + handleStatusChange({'isOnline': id % 2 == 0}); static void unsubscribeFromFriendStatus(int id, Function handleStatusChange) => handleStatusChange({'isOnline': false}); @@ -476,7 +480,7 @@ StateHook useFriendStatus(int friendID) { final isOnline = useState(false); void handleStatusChange(Map status) { - isOnline.set(status['isOnline']); + isOnline.set(status['isOnline'] as bool); } useEffect(() { @@ -492,8 +496,8 @@ StateHook useFriendStatus(int friendID) { return isOnline; } -final FriendListItem = react.registerFunctionComponent((Map props) { - final isOnline = useFriendStatus(props['friend']['id']); +final FriendListItem = react.registerFunctionComponent((props) { + final isOnline = useFriendStatus(props['friend']['id'] as int); return react.li({ 'style': {'color': isOnline.value ? 'green' : 'black'} @@ -503,7 +507,7 @@ final FriendListItem = react.registerFunctionComponent((Map props) { }, displayName: 'FriendListItem'); final UseDebugValueTestComponent = react.registerFunctionComponent( - (Map props) => react.Fragment({}, [ + (props) => react.Fragment({}, [ FriendListItem({ 'key': 'friend1', 'friend': {'id': 1, 'name': 'user 1'}, diff --git a/example/test/get_dom_node_test.dart b/example/test/get_dom_node_test.dart index 08f1b587..2d1bc5c2 100644 --- a/example/test/get_dom_node_test.dart +++ b/example/test/get_dom_node_test.dart @@ -1,23 +1,26 @@ // ignore_for_file: deprecated_member_use_from_same_package -import "dart:html"; +import 'dart:html'; -import "package:react/react.dart" as react; -import "package:react/react_dom.dart" as react_dom; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; -customAssert(text, condition) { - if (condition) - print("${text} passed"); - else - throw (text); +// ignore: avoid_positional_boolean_parameters +void customAssert(String text, bool condition) { + if (condition) { + print('$text passed'); + } else { + throw Exception(text); + } } -var ChildComponent = react.registerComponent(() => new _ChildComponent()); +var ChildComponent = react.registerComponent(() => _ChildComponent()); class _ChildComponent extends react.Component { var counter = 0; + @override render() => react.div({}, [ - "Test element", + 'Test element', counter.toString(), react.button({ 'type': 'button', @@ -31,31 +34,35 @@ class _ChildComponent extends react.Component { ]); } -var simpleComponent = react.registerComponent(() => new SimpleComponent()); +var simpleComponent = react.registerComponent(() => SimpleComponent()); class SimpleComponent extends react.Component { var refToSpan; var refToElement; - componentWillMount() => print("mount"); + @override + componentWillMount() => print('mount'); - componentWillUnmount() => print("unmount"); + @override + componentWillUnmount() => print('unmount'); + @override componentDidMount() { - customAssert("ref to span return span ", refToSpan.text == "Test"); - customAssert("findDOMNode works on this", react_dom.findDOMNode(this) != null); - customAssert("random ref resolves to null", this.ref("someRandomRef") == null); + customAssert('ref to span return span ', refToSpan.text == 'Test'); + customAssert('findDOMNode works on this', react_dom.findDOMNode(this) != null); + customAssert('random ref resolves to null', ref('someRandomRef') == null); } var counter = 0; + @override render() => react.div({}, [ react.span({ 'key': 'span1', - "ref": (ref) { + 'ref': (ref) { refToSpan = ref; } - }, "Test"), + }, 'Test'), react.span({'key': 'span2'}, counter), react.button({ 'type': 'button', @@ -66,7 +73,7 @@ class SimpleComponent extends react.Component { react.br({'key': 'br'}), ChildComponent({ 'key': 'child', - "ref": (ref) { + 'ref': (ref) { refToElement = ref; } }), @@ -82,6 +89,6 @@ class SimpleComponent extends react.Component { var mountedNode = querySelector('#content'); void main() { - var component = simpleComponent({}); + final component = simpleComponent({}); react_dom.render(component, mountedNode); } diff --git a/example/test/order_test.dart b/example/test/order_test.dart index a932e552..d8cc5c65 100644 --- a/example/test/order_test.dart +++ b/example/test/order_test.dart @@ -1,25 +1,28 @@ // ignore_for_file: deprecated_member_use_from_same_package import 'dart:html'; -import "package:react/react.dart" as react; -import "package:react/react_dom.dart" as react_dom; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; class _Item extends react.Component { + @override componentWillReceiveProps(newProps) { - print("Old props: $props"); - print("New props: $newProps"); + print('Old props: $props'); + print('New props: $newProps'); } + @override shouldComponentUpdate(nextProps, nextState) { return false; } + @override render() { return react.li({}, [props['text']]); } } -var item = react.registerComponent(() => new _Item()); +var item = react.registerComponent(() => _Item()); class _List extends react.Component { var items = ['item1', 'item2', 'item3']; @@ -29,12 +32,13 @@ class _List extends react.Component { redraw(); } + @override render() { return react.ul({'onClick': (e) => remove()}, items.map((text) => item({'text': text, 'key': text}))); } } -var list = react.registerComponent(() => new _List()); +var list = react.registerComponent(() => _List()); void main() { react_dom.render(list({}), querySelector('#content')); diff --git a/example/test/react_test.dart b/example/test/react_test.dart index 122d917f..021303e4 100644 --- a/example/test/react_test.dart +++ b/example/test/react_test.dart @@ -1,8 +1,8 @@ -import "dart:html"; +import 'dart:html'; -import "package:react/react_dom.dart" as react_dom; +import 'package:react/react_dom.dart' as react_dom; -import "react_test_components.dart"; +import 'react_test_components.dart'; void main() { react_dom.render( diff --git a/example/test/react_test_components.dart b/example/test/react_test_components.dart index 38de31e2..6a0db285 100644 --- a/example/test/react_test_components.dart +++ b/example/test/react_test_components.dart @@ -1,14 +1,14 @@ // ignore_for_file: deprecated_member_use_from_same_package -import "dart:async"; +import 'dart:async'; -import "package:react/react.dart" as react; -import "package:react/react_dom.dart" as react_dom; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; class _HelloComponent extends react.Component2 { @override get propTypes => { 'name': (Map props, info) { - String propValue = props[info.propName]; + final propValue = props[info.propName] as String; if (propValue.length > 20) { return ArgumentError('($propValue) is too long. $propValue has a max length of 20 characters.'); } @@ -16,23 +16,26 @@ class _HelloComponent extends react.Component2 { }, }; + @override render() { return react.span({}, ["Hello ${props['name']}!"]); } } -var helloComponent = react.registerComponent(() => new _HelloComponent()); +var helloComponent = react.registerComponent(() => _HelloComponent()); class _HelloGreeter extends react.Component { var myInput; - getInitialState() => {"name": "World"}; + @override + getInitialState() => {'name': 'World'}; onInputChange(e) { - var input = react_dom.findDOMNode(myInput); + final input = react_dom.findDOMNode(myInput); print(input.borderEdge); setState({'name': e.target.value}); } + @override render() { return react.div({}, [ react.input({ @@ -47,15 +50,19 @@ class _HelloGreeter extends react.Component { } } -var helloGreeter = react.registerComponent(() => new _HelloGreeter()); +var helloGreeter = react.registerComponent(() => _HelloGreeter()); class _CheckBoxComponent extends react.Component { - getInitialState() => {"checked": false}; + @override + getInitialState() => {'checked': false}; + + bool get checked => state['checked'] as bool; _handleChange(e) { - this.setState({'checked': e.target.checked}); + setState({'checked': e.target.checked}); } + @override render() { return react.div({ 'className': 'form-check' @@ -65,94 +72,105 @@ class _CheckBoxComponent extends react.Component { 'key': 'input', 'className': 'form-check-input', 'type': 'checkbox', - 'checked': state['checked'], + 'checked': checked, 'onChange': _handleChange, }), react.label({ 'htmlFor': 'doTheDishes', 'key': 'label', - 'className': 'form-check-label ' + (this.state['checked'] ? 'striked' : 'not-striked') + 'className': 'form-check-label ${checked ? 'striked' : 'not-striked'}' }, 'do the dishes'), ]); } } -var checkBoxComponent = react.registerComponent(() => new _CheckBoxComponent()); +var checkBoxComponent = react.registerComponent(() => _CheckBoxComponent()); class _ClockComponent extends react.Component { Timer timer; + @override getInitialState() => {'secondsElapsed': 0}; - Map getDefaultProps() => {'refreshRate': 1000}; + @override + getDefaultProps() => {'refreshRate': 1000}; - void componentWillMount() { - timer = new Timer.periodic(new Duration(milliseconds: this.props["refreshRate"]), this.tick); + @override + componentWillMount() { + timer = Timer.periodic(Duration(milliseconds: props['refreshRate'] as int), tick); } - void componentWillUnmount() { + @override + componentWillUnmount() { timer.cancel(); } - void componentDidMount() { - var rootNode = react_dom.findDOMNode(this); - rootNode.style.backgroundColor = "#FFAAAA"; + @override + componentDidMount() { + final rootNode = react_dom.findDOMNode(this); + rootNode.style.backgroundColor = '#FFAAAA'; } - bool shouldComponentUpdate(nextProps, nextState) { + @override + shouldComponentUpdate(nextProps, nextState) { //print("Next state: $nextState, props: $nextProps"); //print("Old state: $state, props: $props"); return nextState['secondsElapsed'] % 2 == 1; } - void componentWillReceiveProps(nextProps) { - print("Received props: $nextProps"); + @override + componentWillReceiveProps(nextProps) { + print('Received props: $nextProps'); } tick(Timer timer) { setState({'secondsElapsed': state['secondsElapsed'] + 1}); } + @override render() { - return react.span({'onClick': (event) => print("Hello World!")}, + return react.span({'onClick': (event) => print('Hello World!')}, // { 'onClick': (event, [domid = null]) => print("Hello World!") }, - ["Seconds elapsed: ", "${state['secondsElapsed']}"]); + ['Seconds elapsed: ', "${state['secondsElapsed']}"]); } } -var clockComponent = react.registerComponent(() => new _ClockComponent()); +var clockComponent = react.registerComponent(() => _ClockComponent()); class _ListComponent extends react.Component { - Map getInitialState() { + @override + getInitialState() { return { - "items": new List.from([0, 1, 2, 3]) + 'items': List.from([0, 1, 2, 3]) }; } - void componentWillUpdate(nextProps, nextState) { - if (nextState["items"].length > state["items"].length) { - print("Adding " + nextState["items"].last.toString()); + @override + componentWillUpdate(nextProps, nextState) { + if ((nextState['items'] as List).length > (state['items'] as List).length) { + print('Adding ' + (nextState['items'] as List).last.toString()); } } - void componentDidUpdate(prevProps, prevState) { - if (prevState["items"].length > state["items"].length) { - print("Removed " + prevState["items"].first.toString()); + @override + componentDidUpdate(prevProps, prevState) { + if ((prevState['items'] as List).length > (state['items'] as List).length) { + print('Removed ' + (prevState['items'] as List).first.toString()); } } int iterator = 3; void addItem(event) { - List items = new List.from(state["items"]); - items.add(++iterator); - setState({"items": items}); + final items = [...state['items'] as List, ++iterator]; + setState({'items': items}); } - dynamic render() { - List items = []; - for (var item in state['items']) { - items.add(react.li({"key": item}, "$item")); + @override + render() { + final items = []; + for (final item in state['items']) { + items.add(react.li({'key': item}, '$item')); } return react.div({}, [ @@ -167,30 +185,32 @@ class _ListComponent extends react.Component { } } -var listComponent = react.registerComponent(() => new _ListComponent()); +var listComponent = react.registerComponent(() => _ListComponent()); class _MainComponent extends react.Component { + @override render() { return react.div({}, props['children']); } } -var mainComponent = react.registerComponent(() => new _MainComponent()); +var mainComponent = react.registerComponent(() => _MainComponent()); ///// // REACT OLD CONTEXT COMPONENTS ///// class _LegacyContextComponent extends react.Component { @override - Iterable get childContextKeys => const ['foo', 'bar', 'renderCount']; + get childContextKeys => const ['foo', 'bar', 'renderCount']; @override - Map getChildContext() => { + getChildContext() => { 'foo': {'object': 'with value'}, 'bar': true, - 'renderCount': this.state['renderCount'] + 'renderCount': state['renderCount'] }; + @override render() { return react.ul({ 'key': 'ul' @@ -206,16 +226,17 @@ class _LegacyContextComponent extends react.Component { } _onButtonClick(event) { - this.setState({'renderCount': (this.state['renderCount'] ?? 0) + 1}); + setState({'renderCount': (state['renderCount'] ?? 0) + 1}); } } -var legacyContextComponent = react.registerComponent(() => new _LegacyContextComponent()); +var legacyContextComponent = react.registerComponent(() => _LegacyContextComponent()); class _LegacyContextConsumerComponent extends react.Component { @override - Iterable get contextKeys => const ['foo']; + get contextKeys => const ['foo']; + @override render() { return react.ul({ 'key': 'ul' @@ -229,12 +250,13 @@ class _LegacyContextConsumerComponent extends react.Component { } } -var legacyContextConsumerComponent = react.registerComponent(() => new _LegacyContextConsumerComponent()); +var legacyContextConsumerComponent = react.registerComponent(() => _LegacyContextConsumerComponent()); class _GrandchildLegacyContextConsumerComponent extends react.Component { @override - Iterable get contextKeys => const ['renderCount']; + get contextKeys => const ['renderCount']; + @override render() { return react.ul({ 'key': 'ul' @@ -246,12 +268,13 @@ class _GrandchildLegacyContextConsumerComponent extends react.Component { } var grandchildLegacyContextConsumerComponent = - react.registerComponent(() => new _GrandchildLegacyContextConsumerComponent()); + react.registerComponent(() => _GrandchildLegacyContextConsumerComponent()); //// // REACT NEW CONTEXT COMPONENTS //// class _NewContextRefComponent extends react.Component2 { + @override render() { return react.div({}, props['children']); } @@ -261,10 +284,10 @@ class _NewContextRefComponent extends react.Component2 { } } -var newContextRefComponent = react.registerComponent(() => new _NewContextRefComponent()); +var newContextRefComponent = react.registerComponent(() => _NewContextRefComponent()); int calculateChangedBits(currentValue, nextValue) { - int result = 1 << 1; + var result = 1 << 1; if (nextValue['renderCount'] % 2 == 0) { result |= 1 << 2; } @@ -276,14 +299,16 @@ var TestNewContext = react.createContext({'renderCount': 0}, calculateChang class _NewContextProviderComponent extends react.Component2 { _NewContextRefComponent componentRef; + @override get initialState => {'renderCount': 0, 'complexMap': false}; printMe() { print('printMe!'); } + @override render() { - final provideMap = {'renderCount': this.state['renderCount']}; + final provideMap = {'renderCount': state['renderCount']}; final complexValues = { 'callback': printMe, @@ -295,14 +320,14 @@ class _NewContextProviderComponent extends react.Component2 { 'componentRef': componentRef, }; - if (state['complexMap']) { + if (state['complexMap'] as bool) { provideMap.addAll(complexValues); } - Map newContextRefComponentProps = { + final newContextRefComponentProps = { 'key': 'ref2', 'ref': (ref) { - componentRef = ref; + componentRef = ref as _NewContextRefComponent; } }; @@ -323,7 +348,7 @@ class _NewContextProviderComponent extends react.Component2 { 'onClick': _onComplexClick, }, 'Redraw With Complex Value'), react.br({'key': 'break1'}), - 'TestContext.Provider props.value: ${provideMap}', + 'TestContext.Provider props.value: $provideMap', react.br({'key': 'break2'}), react.br({'key': 'break3'}), TestNewContext.Provider( @@ -334,23 +359,24 @@ class _NewContextProviderComponent extends react.Component2 { } _onComplexClick(event) { - this.setState({'complexMap': true, 'renderCount': this.state['renderCount'] + 1}); + setState({'complexMap': true, 'renderCount': state['renderCount'] + 1}); } _onButtonClick(event) { - this.setState({'renderCount': this.state['renderCount'] + 1, 'complexMap': false}); + setState({'renderCount': state['renderCount'] + 1, 'complexMap': false}); } } -var newContextProviderComponent = react.registerComponent(() => new _NewContextProviderComponent()); +var newContextProviderComponent = react.registerComponent(() => _NewContextProviderComponent()); class _NewContextConsumerComponent extends react.Component2 { + @override render() { return TestNewContext.Consumer({'unstable_observedBits': props['unstable_observedBits']}, (value) { return react.ul({ 'key': 'ul1' }, [ - 'TestContext.Consumer: value = ${value}', + 'TestContext.Consumer: value = $value', react.br({'key': 'break12'}), react.br({'key': 'break22'}), props['children'], @@ -359,15 +385,16 @@ class _NewContextConsumerComponent extends react.Component2 { } } -var newContextConsumerComponent = react.registerComponent(() => new _NewContextConsumerComponent()); +var newContextConsumerComponent = react.registerComponent(() => _NewContextConsumerComponent()); class _NewContextConsumerObservedBitsComponent extends react.Component2 { + @override render() { return TestNewContext.Consumer({'unstable_observedBits': props['unstable_observedBits']}, (value) { return react.ul({ 'key': 'ul2' }, [ - 'TestContext.Consumer (with unstable_observedBits set to trigger when `renderCount % 2 == 0`): value = ${value}', + 'TestContext.Consumer (with unstable_observedBits set to trigger when `renderCount % 2 == 0`): value = $value', react.br({'key': 'break13'}), react.br({'key': 'break23'}), props['children'], @@ -376,73 +403,79 @@ class _NewContextConsumerObservedBitsComponent extends react.Component2 { } } -var newContextConsumerObservedBitsComponent = - react.registerComponent(() => new _NewContextConsumerObservedBitsComponent()); +var newContextConsumerObservedBitsComponent = react.registerComponent(() => _NewContextConsumerObservedBitsComponent()); class _NewContextTypeConsumerComponent extends react.Component2 { @override final contextType = TestNewContext; + @override render() { - this.context['componentRef']?.test(); + context['componentRef']?.test(); return react.ul({ 'key': 'ul3' }, [ - 'Using Component.contextType: this.context = ${this.context}', + 'Using Component.contextType: this.context = $context', ]); } } class _Component2TestComponent extends react.Component2 with react.TypedSnapshot { + @override get defaultProps => {'defaultProp': true}; + @override get initialState => {'defaultState': true, 'items': []}; - Map getDerivedStateFromProps(nextProps, prevState) { - final prevItems = prevState['items']; + @override + getDerivedStateFromProps(nextProps, prevState) { + final prevItems = prevState['items'] as List; if (prevItems.isEmpty || prevItems[0] != 3) { - return ({ - 'items': new List.from([3, 1, 2, 0]) - }); + return { + 'items': List.from([3, 1, 2, 0]) + }; } return null; } - String getSnapshotBeforeUpdate(nextProps, prevState) { - if (prevState["items"].length > state["items"].length) { - return "removed " + prevState["items"].last.toString(); + @override + getSnapshotBeforeUpdate(nextProps, prevState) { + if ((prevState['items'] as List).length > (state['items'] as List).length) { + return 'removed ' + (prevState['items'].last as List).toString(); } else { - return "added " + state["items"].last.toString(); + return 'added ' + (state['items'].last as List).toString(); } } - void componentDidUpdate(prevProps, prevState, [String snapshot]) { + @override + componentDidUpdate(prevProps, prevState, [String snapshot]) { if (snapshot != null) { - print('Updated DOM and ' + snapshot); - return null; + print('Updated DOM and $snapshot'); + return; } - print("No Snapshot"); + print('No Snapshot'); } void removeItem(event) { - List items = new List.from(state["items"]); + final items = List.from(state['items'] as List); items.removeAt(items.length - 1); - setState({"items": items}); + setState({'items': items}); } void addItem(event) { - List items = new List.from(state["items"]); + final items = List.from(state['items'] as List); items.add(items.length); - setState({"items": items}); + setState({'items': items}); } - dynamic render() { + @override + render() { // Used to generate unique keys even when the list contains duplicate items final itemCounts = {}; final items = []; - for (var item in state['items']) { + for (final item in state['items']) { final count = itemCounts[item] = (itemCounts[item] ?? 0) + 1; - items.add(react.li({'key': 'c2-$item-$count'}, "$item")); + items.add(react.li({'key': 'c2-$item-$count'}, '$item')); } return react.div({}, [ @@ -463,25 +496,27 @@ class _Component2TestComponent extends react.Component2 with react.TypedSnapshot } } -var newContextTypeConsumerComponentComponent = react.registerComponent(() => new _NewContextTypeConsumerComponent()); -var component2TestComponent = react.registerComponent(() => new _Component2TestComponent()); +var newContextTypeConsumerComponentComponent = react.registerComponent(() => _NewContextTypeConsumerComponent()); +var component2TestComponent = react.registerComponent(() => _Component2TestComponent()); class _ErrorComponent extends react.Component2 { - void componentDidMount() { - if (!props["errored"]) { - throw new _CustomException("It broke!", 2); + @override + componentDidMount() { + if (!(props['errored'] as bool)) { + throw _CustomException('It broke!', 2); } } - dynamic render() { + @override + render() { return react.div( {'key': 'eb-d1-e'}, - "Oh no, I'm an error! Check your " - "console."); + 'Oh no, I\'m an error! Check your ' + 'console.'); } } -var ErrorComponent = react.registerComponent(() => new _ErrorComponent()); +var ErrorComponent = react.registerComponent(() => _ErrorComponent()); class _CustomException implements Exception { int code; @@ -491,76 +526,74 @@ class _CustomException implements Exception { _CustomException(this.message, this.code) { switch (code) { case 1: - randomMessage = "The code is a 1"; + randomMessage = 'The code is a 1'; break; case 2: - randomMessage = "The Code is a 2"; + randomMessage = 'The Code is a 2'; break; default: - randomMessage = "Default Error Code"; + randomMessage = 'Default Error Code'; } } } class _Component2ErrorTestComponent extends react.Component2 { - Map get initialState => { - "clicked": false, - "errored": false, - "error": null, + @override + get initialState => { + 'clicked': false, + 'errored': false, + 'error': null, }; - void componentDidCatch(error, info) { + @override + componentDidCatch(error, info) { if (error is _CustomException) { print(info.dartStackTrace); - setState({"error": error.randomMessage}); + setState({'error': error.randomMessage}); } else { - setState({ - "error": "We can capture the error, store it in state and " - "display it here." - }); + setState({'error': 'We can capture the error, store it in state and display it here.'}); } } - Map getDerivedStateFromError(error) { - return {"errored": true}; + @override + getDerivedStateFromError(error) { + return {'errored': true}; } void error(event) { - setState({"clicked": true}); + setState({'clicked': true}); } void clearError(event) { - setState({"clicked": false, "error": null, "errored": false}); + setState({'clicked': false, 'error': null, 'errored': false}); } - dynamic render() { - dynamic errorMessage = state["error"] ?? "No error yet"; + @override + render() { + final errorMessage = state['error'] ?? 'No error yet'; return react.div({ - "key": "e-cont" + 'key': 'e-cont' }, [ - react.h3({"key": "e-header"}, "Error Boundary Test"), - state["clicked"] ? ErrorComponent({'key': 'ec-1', 'errored': state['errored']}) : null, + react.h3({'key': 'e-header'}, 'Error Boundary Test'), + state['clicked'] as bool ? ErrorComponent({'key': 'ec-1', 'errored': state['errored']}) : null, errorMessage != null ? react.div({'key': 'ec-m-1'}, '$errorMessage') : null, - !state["errored"] - ? react.button({ - 'type': 'button', - 'key': 'c3-r-button', - 'className': 'btn btn-primary', - 'onClick': error, - }, 'Trigger Error') - : null, - state["errored"] + state['errored'] as bool ? react.button({ 'type': 'button', 'key': 'c3-c-button', 'className': 'btn btn-primary', 'onClick': clearError, }, 'Clear Error') - : null, - react.hr({"key": "e-hr"}), + : react.button({ + 'type': 'button', + 'key': 'c3-r-button', + 'className': 'btn btn-primary', + 'onClick': error, + }, 'Trigger Error'), + react.hr({'key': 'e-hr'}), ]); } } -var component2ErrorTestComponent = react.registerComponent(() => new _Component2ErrorTestComponent(), ['render']); +var component2ErrorTestComponent = react.registerComponent(() => _Component2ErrorTestComponent(), ['render']); diff --git a/example/test/ref_test.dart b/example/test/ref_test.dart index 690c0832..248dd73f 100644 --- a/example/test/ref_test.dart +++ b/example/test/ref_test.dart @@ -1,11 +1,11 @@ // ignore_for_file: deprecated_member_use_from_same_package -import "dart:html"; +import 'dart:html'; -import "package:react/react.dart" as react; -import "package:react/react_dom.dart" as react_dom; -import "package:react/react_client.dart"; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; +import 'package:react/react_client.dart'; -var ChildComponent = react.registerComponent(() => new _ChildComponent()); +var ChildComponent = react.registerComponent(() => _ChildComponent()); class _ChildComponent extends react.Component { int somevalue = 10; @@ -14,7 +14,8 @@ class _ChildComponent extends react.Component { redraw(); } - render() => react.span({}, "Child element with value ${somevalue}"); + @override + render() => react.span({}, 'Child element with value $somevalue'); } var InputComponentForm = react.forwardRef2((props, ref) { @@ -39,14 +40,14 @@ var InputComponentForm = react.forwardRef2((props, ref) { var ChildComponentForm = react.forwardRef2((props, ref) { return react.Fragment({}, [ - react.h4({'key': 'create-child-h4'}, "ChildComponent"), + react.h4({'key': 'create-child-h4'}, 'ChildComponent'), react.form({ 'key': 'childComponentForm', 'className': 'form-inline' }, [ ChildComponent({ 'key': 'create-child', - "ref": ref, + 'ref': ref, }), '\u00a0', react.button({ @@ -66,28 +67,28 @@ var ChildComponentForm = react.forwardRef2((props, ref) { ]); }, displayName: 'ChildComponentForm'); -var ParentComponent = react.registerComponent(() => new _ParentComponent()); +var ParentComponent = react.registerComponent(() => _ParentComponent()); class _ParentComponent extends react.Component { // String refs showInputValue(_) { - var input = react_dom.findDOMNode(ref('inputRef')) as InputElement; + final input = react_dom.findDOMNode(ref('inputRef')) as InputElement; print(input.value); } showChildValue(_) { - print(ref("childRef").somevalue); + print(ref('childRef').somevalue); } incrementChildValue(_) { - ref("childRef").incrementValue(); + ref('childRef').incrementValue(); } // Callback refs InputElement _inputCallbackRef; _ChildComponent _childCallbackRef; showInputCallbackRefValue(_) { - var input = react_dom.findDOMNode(_inputCallbackRef); + final input = react_dom.findDOMNode(_inputCallbackRef) as InputElement; print(input.value); } @@ -104,7 +105,7 @@ class _ParentComponent extends react.Component { final Ref<_ChildComponent> _childCreateRef = react.createRef(); showInputCreateRefValue(_) { - var input = react_dom.findDOMNode(_inputCreateRef.current); + final input = react_dom.findDOMNode(_inputCreateRef.current) as InputElement; print(input.value); } @@ -116,13 +117,14 @@ class _ParentComponent extends react.Component { _childCreateRef.current.incrementValue(); } + @override render() => react.div({}, [ react.h1({'key': 'h1'}, 'Refs'), react.div({ 'key': 'string-refs' }, [ - react.h2({'key': 'string-h2'}, "String refs"), - react.h4({'key': 'string-h4'}, ""), + react.h2({'key': 'string-h2'}, 'String refs'), + react.h4({'key': 'string-h4'}, ''), react.form({ 'key': 'stringRefInputForm', 'className': 'form-inline' @@ -140,12 +142,12 @@ class _ParentComponent extends react.Component { 'onClick': showInputValue, }, 'Print input element value'), ]), - react.h4({'key': 'string-h4-child'}, "ChildComponent"), + react.h4({'key': 'string-h4-child'}, 'ChildComponent'), react.form({ 'key': 'stringRefChildComponentForm', 'className': 'form-inline' }, [ - ChildComponent({'key': 'string-child', "ref": "childRef"}), + ChildComponent({'key': 'string-child', 'ref': 'childRef'}), '\u00a0', react.button({ 'type': 'button', @@ -165,8 +167,8 @@ class _ParentComponent extends react.Component { react.div({ 'key': 'callback-refs' }, [ - react.h2({'key': 'h2-callback'}, "Callback refs"), - react.h4({'key': 'h4-callback-input'}, ""), + react.h2({'key': 'h2-callback'}, 'Callback refs'), + react.h4({'key': 'h4-callback-input'}, ''), react.form({ 'key': 'inputForm', 'className': 'form-inline' @@ -174,7 +176,7 @@ class _ParentComponent extends react.Component { react.input({ 'key': 'callback-input', 'className': 'form-control', - 'ref': (instance) => _inputCallbackRef = instance, + 'ref': (instance) => _inputCallbackRef = instance as InputElement, }), '\u00a0', react.button({ @@ -184,14 +186,14 @@ class _ParentComponent extends react.Component { 'onClick': showInputCallbackRefValue, }, 'Print input element value'), ]), - react.h4({'key': 'callback-child-h4'}, "ChildComponent"), + react.h4({'key': 'callback-child-h4'}, 'ChildComponent'), react.form({ 'key': 'childComponentForm', 'className': 'form-inline' }, [ ChildComponent({ 'key': 'callback-child', - "ref": (instance) => _childCallbackRef = instance, + 'ref': (instance) => _childCallbackRef = instance as _ChildComponent, }), '\u00a0', react.button({ @@ -212,8 +214,8 @@ class _ParentComponent extends react.Component { react.div({ 'key': 'forward-refs' }, [ - react.h2({'key': 'h2-forward'}, "Create / Forward refs"), - react.h4({'key': 'h4-forward-input'}, ""), + react.h2({'key': 'h2-forward'}, 'Create / Forward refs'), + react.h4({'key': 'h4-forward-input'}, ''), InputComponentForm({ 'ref': _inputCreateRef, 'showInputForwardRefValue': showInputCreateRefValue, @@ -231,6 +233,6 @@ class _ParentComponent extends react.Component { var mountedNode = querySelector('#content'); void main() { - var component = ParentComponent({}); + final component = ParentComponent({}); react_dom.render(component, mountedNode); } diff --git a/example/test/speed_test.dart b/example/test/speed_test.dart index d887c484..057e5a93 100644 --- a/example/test/speed_test.dart +++ b/example/test/speed_test.dart @@ -1,43 +1,48 @@ // ignore_for_file: deprecated_member_use_from_same_package -import "dart:html"; -import "dart:async"; +import 'dart:html'; +import 'dart:async'; -import "package:react/react.dart" as react; -import "package:react/react_dom.dart" as react_dom; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; -Stopwatch stopwatch = new Stopwatch()..start(); +Stopwatch stopwatch = Stopwatch()..start(); timeprint(message) { - print("$message ${stopwatch.elapsedMilliseconds}"); + print('$message ${stopwatch.elapsedMilliseconds}'); stopwatch.reset(); } class _Div extends react.Component { + @override shouldComponentUpdate(nProps, nState) { return nProps['key'] != props['key']; } + @override render() { return react.div(props, props['children']); } } -var Div = react.registerComponent(() => new _Div()); +var Div = react.registerComponent(() => _Div()); class _Span extends react.Component { + @override shouldComponentUpdate(nProps, nState) { return nProps['children'][0] != props['children'][0]; } + @override render() { return react.span(props, props['children']); } } -var Span = react.registerComponent(() => new _Span()); +var Span = react.registerComponent(() => _Span()); class _Hello extends react.Component { + @override componentWillMount() { - new Future.delayed(new Duration(seconds: 5), () { + Future.delayed(Duration(seconds: 5), () { stopwatch.reset(); timeprint('before redraw call'); redraw(); @@ -45,16 +50,17 @@ class _Hello extends react.Component { }); } + @override render() { - timeprint("rendering start"); - var data = props['data']; - var children = []; - for (var elem in data) { + timeprint('rendering start'); + final data = props['data']; + final children = []; + for (final elem in data) { children.add(react.div({ 'key': elem[0] }, [ react.span({'key': 'span1'}, elem[0]), - " ", + ' ', react.span({'key': 'span2'}, elem[1]) ])); } @@ -65,19 +71,19 @@ class _Hello extends react.Component { // react.span({}, elem[1]) // ])) // ); - timeprint("rendering almost ends"); - var res = react.div({}, children); - timeprint("rendering ends"); + timeprint('rendering almost ends'); + final res = react.div({}, children); + timeprint('rendering ends'); return res; } } -var Hello = react.registerComponent(() => new _Hello()); +var Hello = react.registerComponent(() => _Hello()); void main() { - var data = []; + final data = []; for (num i = 0; i < 1000; i++) { - data.add(["name_$i", "value_$i"]); + data.add(['name_$i', 'value_$i']); } - react_dom.render(Hello({"data": data}, []), querySelector('#content')); + react_dom.render(Hello({'data': data}, []), querySelector('#content')); } diff --git a/example/test/unmount_test.dart b/example/test/unmount_test.dart index 1cb4b1d5..2cb484a2 100644 --- a/example/test/unmount_test.dart +++ b/example/test/unmount_test.dart @@ -1,24 +1,27 @@ // ignore_for_file: deprecated_member_use_from_same_package -import "dart:html"; +import 'dart:html'; -import "package:react/react.dart" as react; -import "package:react/react_dom.dart" as react_dom; +import 'package:react/react.dart' as react; +import 'package:react/react_dom.dart' as react_dom; -var simpleComponent = react.registerComponent(() => new SimpleComponent()); +var simpleComponent = react.registerComponent(() => SimpleComponent()); class SimpleComponent extends react.Component { - componentWillMount() => print("mount"); + @override + componentWillMount() => print('mount'); - componentWillUnmount() => print("unmount"); + @override + componentWillUnmount() => print('unmount'); + @override render() => react.div({}, [ - "Simple component", + 'Simple component', ]); } void main() { - print("What"); - var mountedNode = querySelector('#content'); + print('What'); + final mountedNode = querySelector('#content'); querySelector('#mount').onClick.listen((_) => react_dom.render(simpleComponent({}), mountedNode)); diff --git a/lib/hooks.dart b/lib/hooks.dart index 9fe1df67..c83348f5 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -25,18 +25,18 @@ class StateHook { StateHook(T initialValue) { final result = React.useState(initialValue); - _value = result[0]; - _setValue = result[1]; + _value = result[0] as T; + _setValue = result[1] as void Function(dynamic); } /// Constructor for [useStateLazy], calls lazy version of [React.useState] to /// initialize [_value] to the return value of [init]. /// /// See: . - StateHook.lazy(T init()) { + StateHook.lazy(T Function() init) { final result = React.useState(allowInterop(init)); - _value = result[0]; - _setValue = result[1]; + _value = result[0] as T; + _setValue = result[1] as void Function(dynamic); } /// The current value of the state. @@ -52,7 +52,7 @@ class StateHook { /// Updates [value] to the return value of [computeNewValue]. /// /// See: . - void setWithUpdater(T computeNewValue(T oldValue)) => _setValue(allowInterop(computeNewValue)); + void setWithUpdater(T Function(T oldValue) computeNewValue) => _setValue(allowInterop(computeNewValue)); } /// Adds local state to a [DartFunctionComponent] @@ -100,7 +100,7 @@ StateHook useState(T initialValue) => StateHook(initialValue); /// ``` /// /// Learn more: . -StateHook useStateLazy(T init()) => StateHook.lazy(init); +StateHook useStateLazy(T Function() init) => StateHook.lazy(init); /// Runs [sideEffect] after every completed render of a [DartFunctionComponent]. /// @@ -141,8 +141,8 @@ StateHook useStateLazy(T init()) => StateHook.lazy(init); /// /// See: . void useEffect(dynamic Function() sideEffect, [List dependencies]) { - var wrappedSideEffect = allowInterop(() { - var result = sideEffect(); + final wrappedSideEffect = allowInterop(() { + final result = sideEffect(); if (result is Function) { return allowInterop(result); } @@ -165,16 +165,16 @@ void useEffect(dynamic Function() sideEffect, [List dependencies]) { /// /// Learn more: . class ReducerHook { - /// The first item of the pair returned by [React.userReducer]. + /// The first item of the pair returned by [React.useReducer]. TState _state; - /// The second item in the pair returned by [React.userReducer]. + /// The second item in the pair returned by [React.useReducer]. void Function(TAction) _dispatch; ReducerHook(TState Function(TState state, TAction action) reducer, TState initialState) { final result = React.useReducer(allowInterop(reducer), initialState); - _state = result[0]; - _dispatch = result[1]; + _state = result[0] as TState; + _dispatch = result[1] as void Function(TAction); } /// Constructor for [useReducerLazy], calls lazy version of [React.useReducer] to @@ -184,8 +184,8 @@ class ReducerHook { ReducerHook.lazy( TState Function(TState state, TAction action) reducer, TInit initialArg, TState Function(TInit) init) { final result = React.useReducer(allowInterop(reducer), initialArg, allowInterop(init)); - _state = result[0]; - _dispatch = result[1]; + _state = result[0] as TState; + _dispatch = result[1] as void Function(TAction); } /// The current state map of the component. @@ -201,7 +201,7 @@ class ReducerHook { void dispatch(TAction action) => _dispatch(action); } -/// Initializes state of a [DartFunctionComponent] to [initialState] and creates [dispatch] method. +/// Initializes state of a [DartFunctionComponent] to [initialState] and creates a `dispatch` method. /// /// __Example__: /// @@ -241,7 +241,7 @@ ReducerHook useReducer( TState Function(TState state, TAction action) reducer, TState initialState) => ReducerHook(reducer, initialState); -/// Initializes state of a [DartFunctionComponent] to [init(initialArg)] and creates [dispatch] method. +/// Initializes state of a [DartFunctionComponent] to `init(initialArg)` and creates `dispatch` method. /// /// __Example__: /// @@ -328,7 +328,7 @@ ReducerHook useReducerLazy( /// /// Learn more: . T useCallback(T callback, List dependencies) => - React.useCallback(allowInterop(callback), dependencies); + React.useCallback(allowInterop(callback), dependencies) as T; /// Returns the value of the nearest [Context.Provider] for the provided [context] object every time that context is /// updated. @@ -426,7 +426,7 @@ Ref useRef([T initialValue]) => Ref.useRefInit(initialValue); /// /// Learn more: . T useMemo(T Function() createFunction, [List dependencies]) => - React.useMemo(allowInterop(createFunction), dependencies); + React.useMemo(allowInterop(createFunction), dependencies) as T; /// Runs [sideEffect] synchronously after a [DartFunctionComponent] renders, but before the screen is updated. /// @@ -581,7 +581,7 @@ void useImperativeHandle(dynamic ref, dynamic Function() createHandle, [List(TProps props, PropValidatorInfo info); +typedef PropValidator = Error Function(TProps props, PropValidatorInfo info); /// A React component declared using a function that takes in [props] and returns rendered output. /// -/// See . +/// See . /// /// [props] is typed as [JsBackedMap] so that dart2js can optimize props accesses. typedef DartFunctionComponent = dynamic Function(JsBackedMap props); @@ -45,19 +44,19 @@ typedef DartFunctionComponent = dynamic Function(JsBackedMap props); /// and not just a ref object, so we type [ref] as dynamic here. typedef DartForwardRefFunctionComponent = dynamic Function(JsBackedMap props, dynamic ref); -typedef T ComponentFactory(); +typedef ComponentFactory = T Function(); -typedef ReactComponentFactoryProxy ComponentRegistrar(ComponentFactory componentFactory, +typedef ComponentRegistrar = ReactComponentFactoryProxy Function(ComponentFactory componentFactory, [Iterable skipMethods]); -typedef ReactDartComponentFactoryProxy2 ComponentRegistrar2( +typedef ComponentRegistrar2 = ReactDartComponentFactoryProxy2 Function( ComponentFactory componentFactory, { Iterable skipMethods, Component2BridgeFactory bridgeFactory, }); -typedef ReactDartFunctionComponentFactoryProxy FunctionComponentRegistrar(DartFunctionComponent componentFactory, - {String displayName}); +typedef FunctionComponentRegistrar = ReactDartFunctionComponentFactoryProxy + Function(DartFunctionComponent componentFactory, {String displayName}); /// Fragment component that allows the wrapping of children without the necessity of using /// an element that adds an additional layer to the DOM (div, span, etc). @@ -67,7 +66,7 @@ var Fragment = ReactJsComponentFactoryProxy(React.Fragment); /// [Suspense] lets you display a fallback UI until its children have finished loading. /// -/// Like [react.Fragment], [Suspense] does not render any visible UI. +/// Like [Fragment], [Suspense] does not render any visible UI. /// It lets you specify a loading indicator in case some components in /// the tree below it are not yet ready to render. /// [Suspense] currently works with: @@ -104,8 +103,8 @@ var Suspense = ReactJsComponentFactoryProxy(React.Suspense); /// See: var StrictMode = ReactJsComponentFactoryProxy(React.StrictMode); -/// Top-level ReactJS [Component class](https://facebook.github.io/react/docs/react-component.html) -/// which provides the [ReactJS Component API](https://facebook.github.io/react/docs/react-component.html#reference) +/// Top-level ReactJS [Component class](https://reactjs.org/docs/react-component.html) +/// which provides the [ReactJS Component API](https://reactjs.org/docs/react-component.html#reference) /// /// __Deprecated. Use [Component2] instead.__ @Deprecated('7.0.0') @@ -155,17 +154,19 @@ abstract class Component { /// > /// > It is strongly recommended that you migrate to [Component2] and use [Component2.context] instead. @experimental - set context(dynamic value) => _context = value; + set context(dynamic value) => _context = value as Map; /// ReactJS [Component] props. /// /// Related: [state] + // ignore: unnecessary_getters_setters Map get props => _props; set props(Map value) => _props = value; /// ReactJS [Component] state. /// /// Related: [props] + // ignore: unnecessary_getters_setters Map get state => _state; set state(Map value) => _state = value; @@ -195,8 +196,10 @@ abstract class Component { dynamic _jsThis; + // ignore: prefer_final_fields List _setStateCallbacks = []; + // ignore: prefer_final_fields List _transactionalSetStateCallbacks = []; /// The List of callbacks to be called after the component has been updated from a call to [setState]. @@ -205,11 +208,11 @@ abstract class Component { /// The List of transactional `setState` callbacks to be called before the component updates. List get transactionalSetStateCallbacks => _transactionalSetStateCallbacks; - /// The JavaScript [`ReactComponent`](https://facebook.github.io/react/docs/top-level-api.html#reactdom.render) + /// The JavaScript [`ReactComponent`](https://reactjs.org/docs/react-api.html#reactdom.render) /// instance of this `Component` returned by [render]. dynamic get jsThis => _jsThis; - /// Allows the [ReactJS `displayName` property](https://facebook.github.io/react/docs/react-component.html#displayname) + /// Allows the [ReactJS `displayName` property](https://reactjs.org/docs/react-component.html#displayname) /// to be set for debugging purposes. String get displayName => runtimeType.toString(); @@ -226,21 +229,21 @@ abstract class Component { /// [context]s typing was loosened from Map to dynamic to support the new context API in [Component2] /// which extends from [Component]. Only "legacy" context APIs are supported in [Component] - which means /// it will still be expected to be a Map. - this.context = new Map.from(context ?? const {}); + this.context = Map.from(context as Map ?? const {}); /// [nextContext]s typing was loosened from Map to dynamic to support the new context API in [Component2] /// which extends from [Component]. Only "legacy" context APIs are supported in [Component] - which means /// it will still be expected to be a Map. - this.nextContext = new Map.from(this.context ?? const {}); + nextContext = Map.from(this.context as Map ?? const {}); } _initProps(props) { - this.props = new Map.from(props); - this.nextProps = this.props; + this.props = Map.from(props as Map); + nextProps = this.props; } initStateInternal() { - this.state = new Map.from(getInitialState()); + state = Map.from(getInitialState()); // Call `transferComponentState` to get state also to `_prevState` transferComponentState(); @@ -289,7 +292,7 @@ abstract class Component { /// Public getter for [_nextState]. /// /// If `null`, then [_nextState] is equal to [state] - which is the value that will be returned. - Map get nextState => _nextState == null ? state : _nextState; + Map get nextState => _nextState ?? state; /// Reference to the value of [props] for the upcoming render cycle. /// @@ -312,13 +315,13 @@ abstract class Component { if (_nextState != null) { state = _nextState; } - _nextState = new Map.from(state); + _nextState = Map.from(state); } /// Force a call to [render] by calling [setState], which effectively "redraws" the `Component`. /// /// Optionally accepts a [callback] that gets called after the component updates. - void redraw([callback()]) { + void redraw([Function() callback]) { setState({}, callback); } @@ -328,14 +331,14 @@ abstract class Component { /// /// Also allows [newState] to be used as a transactional `setState` callback. /// - /// See: - void setState(covariant dynamic newState, [callback()]) { + /// See: + void setState(covariant dynamic newState, [Function() callback]) { if (newState is Map) { _nextState.addAll(newState); } else if (newState is StateUpdaterCallback) { _transactionalSetStateCallbacks.add(newState); } else if (newState != null) { - throw new ArgumentError( + throw ArgumentError( 'setState expects its first parameter to either be a Map or a `TransactionalSetStateCallback`.'); } @@ -348,14 +351,14 @@ abstract class Component { /// /// Optionally accepts a callback that gets called after the component updates. /// - /// See: + /// See: /// /// > __DEPRECATED.__ /// > /// > Use [setState] instead. @Deprecated('7.0.0') - void replaceState(Map newState, [callback()]) { - Map nextState = newState == null ? {} : new Map.from(newState); + void replaceState(Map newState, [Function() callback]) { + final nextState = newState == null ? {} : Map.from(newState); _nextState = nextState; if (callback != null) _setStateCallbacks.add(callback); @@ -368,17 +371,17 @@ abstract class Component { /// If you call [setState] within this method, [render] will see the updated state and will be executed only once /// despite the [state] value change. /// - /// See: + /// See: void componentWillMount() {} /// ReactJS lifecycle method that is invoked once, only on the client _(not on the server)_, immediately after the /// initial rendering occurs. /// - /// At this point in the lifecycle, you can access any [ref]s to the children of [rootNode]. + /// At this point in the lifecycle, you can access any [ref]s to the children of the root node. /// /// The [componentDidMount] method of child `Component`s is invoked _before_ that of parent `Component`. /// - /// See: + /// See: void componentDidMount() {} /// ReactJS lifecycle method that is invoked when a `Component` is receiving [newProps]. @@ -390,7 +393,7 @@ abstract class Component { /// /// Calling [setState] within this function will not trigger an additional [render]. /// - /// See: + /// See: /// > __UNSUPPORTED IN COMPONENT2__ /// > /// > This will be removed once 7.0.0 releases; switching to [Component2.getDerivedStateFromProps] is the path forward. @@ -411,7 +414,7 @@ abstract class Component { /// Use this as an opportunity to return `false` when you're certain that the transition to the new props and state /// will not require a component update. /// - /// See: + /// See: bool shouldComponentUpdate(Map nextProps, Map nextState) => true; /// > __DEPRECATED - DO NOT USE__ @@ -421,6 +424,7 @@ abstract class Component { /// > /// > This will be completely removed when the JS side of it is slated for removal (ReactJS 18 / react.dart 7.0.0) @Deprecated('7.0.0') + // ignore: avoid_returning_null bool shouldComponentUpdateWithContext(Map nextProps, Map nextState, Map nextContext) => null; /// ReactJS lifecycle method that is invoked immediately before rendering when [nextProps] or [nextState] are being @@ -433,7 +437,7 @@ abstract class Component { /// __Note__: Choose either this method or [componentWillUpdateWithContext]. They are both called at the same time so /// using both provides no added benefit. /// - /// See: + /// See: /// /// > __UNSUPPORTED IN COMPONENT2__ /// > @@ -459,18 +463,18 @@ abstract class Component { /// /// This method is not called for the initial [render]. /// - /// Use this as an opportunity to operate on the [rootNode] (DOM) when the `Component` has been updated as a result + /// Use this as an opportunity to operate on the root node (DOM) when the `Component` has been updated as a result /// of the values of [prevProps] / [prevState]. /// - /// See: + /// See: void componentDidUpdate(Map prevProps, Map prevState) {} /// ReactJS lifecycle method that is invoked immediately before a `Component` is unmounted from the DOM. /// - /// Perform any necessary cleanup in this method, such as invalidating timers or cleaning up any DOM [Element]s that + /// Perform any necessary cleanup in this method, such as invalidating timers or cleaning up any DOM `Element`s that /// were created in [componentDidMount]. /// - /// See: + /// See: void componentWillUnmount() {} /// Returns a Map of context to be passed to descendant components. @@ -514,25 +518,25 @@ abstract class Component { /// Invoked once before the `Component` is mounted. The return value will be used as the initial value of [state]. /// - /// See: + /// See: Map getInitialState() => {}; - /// Invoked once and cached when [reactComponentClass] is called. Values in the mapping will be set on [props] + /// Invoked once and cached when [registerComponent] is called. Values in the mapping will be set on [props] /// if that prop is not specified by the parent component. /// /// This method is invoked before any instances are created and thus cannot rely on [props]. In addition, be aware /// that any complex objects returned by `getDefaultProps` will be shared across instances, not copied. /// - /// See: + /// See: Map getDefaultProps() => {}; /// __Required.__ /// - /// When called, it should examine [props] and [state] and return a single child [Element]. This child [Element] can - /// be either a virtual representation of a native DOM component (such as [DivElement]) or another composite + /// When called, it should examine [props] and [state] and return a single child `Element`. This child `Element` can + /// be either a virtual representation of a native DOM component (such as `DivElement`) or another composite /// `Component` that you've defined yourself. /// - /// See: + /// See: dynamic render(); } @@ -564,7 +568,7 @@ abstract class Component { /// 4. Supports React 16 [context] abstract class Component2 implements Component { /// Accessed once and cached when instance is created. The [contextType] property on a class can be assigned - /// a [ReactDartContext] object created by [React.createContext]. This lets you consume the nearest current value of + /// a [ReactContext] object created by [React.createContext]. This lets you consume the nearest current value of /// that Context using [context]. /// /// __Example__: @@ -585,7 +589,7 @@ abstract class Component2 implements Component { /// See: Context get contextType => null; - /// Invoked once and cached when [reactComponentClass] is called. Values in the mapping will be set on [props] + /// Invoked once and cached when [registerComponent] is called. Values in the mapping will be set on [props] /// if that prop is not specified by the parent component. /// /// This method is invoked before any instances are created and thus cannot rely on [props]. In addition, be aware @@ -664,12 +668,12 @@ abstract class Component2 implements Component { @Deprecated('7.0.0') set _jsThis(_) => throw _unsupportedError('_jsThis'); - /// The JavaScript [`ReactComponent`](https://facebook.github.io/react/docs/top-level-api.html#reactdom.render) + /// The JavaScript [`ReactComponent`](https://reactjs.org/docs/react-api.html#reactdom.render) /// instance of this `Component` returned by [render]. @override ReactComponent jsThis; - /// Allows the [ReactJS `displayName` property](https://facebook.github.io/react/docs/react-component.html#displayname) + /// Allows the [ReactJS `displayName` property](https://reactjs.org/docs/react-component.html#displayname) /// to be set for debugging purposes. /// /// In DDC, this will be the class name, but in dart2js it will be null unless @@ -677,8 +681,9 @@ abstract class Component2 implements Component { /// /// This will result in the dart2js name being `ReactDartComponent2` (the /// name of the proxying JS component defined in _dart_helpers.js). + @override String get displayName { - var value; + String value; assert(() { value = runtimeType.toString(); return true; @@ -695,6 +700,7 @@ abstract class Component2 implements Component { /// To use a transactional `setState` callback, check out [setStateWithUpdater]. /// /// See: + @override void setState(Map newState, [SetStateCallback callback]) { _bridge.setState(this, newState, callback); } @@ -719,11 +725,12 @@ abstract class Component2 implements Component { /// ReactJS lifecycle method that is invoked once, only on the client _(not on the server)_, immediately after the /// initial rendering occurs. /// - /// At this point in the lifecycle, you can access any [ref]s to the children of [rootNode]. + /// At this point in the lifecycle, you can access any [ref]s to the children of the root node. /// /// The [componentDidMount] method of child `Component`s is invoked _before_ that of parent `Component`. /// - /// See: + /// See: + @override void componentDidMount() {} /// ReactJS lifecycle method that is invoked before rendering when new props ([nextProps]) are received. @@ -771,6 +778,7 @@ abstract class Component2 implements Component { /// will not require a component update. /// /// See: + @override bool shouldComponentUpdate(Map nextProps, Map nextState) => true; /// ReactJS lifecycle method that is invoked immediately after re-rendering @@ -819,7 +827,7 @@ abstract class Component2 implements Component { /// /// This method is not called for the initial [render]. /// - /// Use this as an opportunity to operate on the [rootNode] (DOM) when the `Component` has been updated as a result + /// Use this as an opportunity to operate on the root node (DOM) when the `Component` has been updated as a result /// of the values of [prevProps] / [prevState]. /// /// __Note__: React 16 added a third parameter to `componentDidUpdate`, which @@ -828,14 +836,16 @@ abstract class Component2 implements Component { /// parameter in `componentDidUpdate` will be null. /// /// See: + @override void componentDidUpdate(Map prevProps, Map prevState, [dynamic snapshot]) {} /// ReactJS lifecycle method that is invoked immediately before a `Component` is unmounted from the DOM. /// - /// Perform any necessary cleanup in this method, such as invalidating timers or cleaning up any DOM [Element]s that + /// Perform any necessary cleanup in this method, such as invalidating timers or cleaning up any DOM `Element`s that /// were created in [componentDidMount]. /// /// See: + @override void componentWillUnmount() {} /// ReactJS lifecycle method that is invoked after an [error] is thrown by a descendant. @@ -910,6 +920,7 @@ abstract class Component2 implements Component { /// ``` /// /// See: + // ignore: prefer_void_to_null Map> get propTypes => {}; /// Examines [props] and [state] and returns one of the following types: @@ -930,6 +941,7 @@ abstract class Component2 implements Component { /// or the other lifecycle methods instead. Keeping `render` pure makes components easier to think about. /// /// See: + @override dynamic render(); // ****************************************************************************************************************** @@ -961,31 +973,33 @@ abstract class Component2 implements Component { // ****************************************************************************************************************** UnsupportedError _unsupportedLifecycleError(String memberName) => - new UnsupportedError('Component2 drops support for the lifecycle method $memberName.' + UnsupportedError('Component2 drops support for the lifecycle method $memberName.' ' See doc comment on Component2.$memberName for migration instructions.'); /// Invoked once before the `Component` is mounted. The return value will be used as the initial value of [state]. /// - /// See: + /// See: /// /// > __DEPRECATED - DO NOT USE__ /// > /// > Use the [initialState] getter instead. + @override @mustCallSuper @Deprecated('7.0.0') Map getInitialState() => throw _unsupportedLifecycleError('getInitialState'); - /// Invoked once and cached when [reactComponentClass] is called. Values in the mapping will be set on [props] + /// Invoked once and cached when [registerComponent] is called. Values in the mapping will be set on [props] /// if that prop is not specified by the parent component. /// /// This method is invoked before any instances are created and thus cannot rely on [props]. In addition, be aware /// that any complex objects returned by `getDefaultProps` will be shared across instances, not copied. /// - /// See: + /// See: /// /// > __DEPRECATED - DO NOT USE__ /// > /// > Use the [defaultProps] getter instead. + @override @mustCallSuper @Deprecated('7.0.0') Map getDefaultProps() => throw _unsupportedLifecycleError('getDefaultProps'); @@ -995,6 +1009,7 @@ abstract class Component2 implements Component { /// > __DEPRECATED - DO NOT USE__ /// > /// > Use [componentDidMount] instead + @override @mustCallSuper @Deprecated('7.0.0') void componentWillMount() => throw _unsupportedLifecycleError('componentWillMount'); @@ -1052,6 +1067,7 @@ abstract class Component2 implements Component { /// /// // NOTE: You could also return a `snapshot` value from this method for later use in `componentDidUpdate`. /// } + @override @mustCallSuper @Deprecated('7.0.0') void componentWillReceiveProps(Map nextProps) => throw _unsupportedLifecycleError('componentWillReceiveProps'); @@ -1094,6 +1110,7 @@ abstract class Component2 implements Component { /// /// // NOTE: You could also return a `snapshot` value from this method for later use in `componentDidUpdate`. /// } + @override @mustCallSuper @Deprecated('7.0.0') void componentWillUpdate(Map nextProps, Map nextState) => throw _unsupportedLifecycleError('componentWillUpdate'); @@ -1145,8 +1162,7 @@ abstract class Component2 implements Component { // Other deprecated and unsupported members // ****************************************************************************************************************** - UnsupportedError _unsupportedError(String memberName) => - new UnsupportedError('Component2 drops support for $memberName'); + UnsupportedError _unsupportedError(String memberName) => UnsupportedError('Component2 drops support for $memberName'); /// Do not use. /// @@ -1210,6 +1226,7 @@ abstract class Component2 implements Component { @override @Deprecated('7.0.0') Map get prevState => throw _unsupportedError('"Legacy" Context [prevContext]'); + @override set prevState(_) => throw _unsupportedError('"Legacy" Context [prevContext]'); /// Do not use. @@ -1225,6 +1242,7 @@ abstract class Component2 implements Component { @override @Deprecated('7.0.0') Map get nextProps => throw _unsupportedError('nextProps'); + @override set nextProps(_) => throw _unsupportedError('nextProps'); /// Do not use. @@ -1240,6 +1258,7 @@ abstract class Component2 implements Component { @override @Deprecated('7.0.0') RefMethod get ref => throw _unsupportedError('ref'); + @override set ref(_) => throw _unsupportedError('ref'); /// Do not use. @@ -1339,12 +1358,12 @@ mixin TypedSnapshot { void componentDidUpdate(Map prevProps, Map prevState, [covariant TSnapshot snapshot]); } -/// Creates a ReactJS virtual DOM instance (`ReactElement` on the client). +/// Creates a ReactJS virtual DOM instance ([ReactElement] on the client). abstract class ReactComponentFactoryProxy implements Function { /// The type of component created by this factory. get type; - /// Returns a new rendered component instance with the specified [props] and [children]. + /// Returns a new rendered component instance with the specified [props] and [childrenArgs]. /// /// Necessary to work around DDC `dart.dcall` issues in , /// since invoking the function directly doesn't work. @@ -1463,31 +1482,31 @@ abstract class ReactComponentFactoryProxy implements Function { } } -const _notSpecified = const NotSpecified(); +const _notSpecified = NotSpecified(); class NotSpecified { const NotSpecified(); } -/// Registers [componentFactory] on both client and server. +/// Registers a component factory on both client and server. @Deprecated('Use registerComponent2 after migrating your components from Component to Component2.') /*ComponentRegistrar*/ Function registerComponent = validateJsApiThenReturn(() => registration_utils.registerComponent); -/// Registers [componentFactory] on both client and server. +/// Registers a component factory on both client and server. ComponentRegistrar2 registerComponent2 = validateJsApiThenReturn(() => registration_utils.registerComponent2); -/// Registers [componentFactory] on client. +/// Registers a function component on the client. /// /// Example: /// ``` -/// var myFunctionComponent = registerFunctionComponent((Map props) { +/// var myFunctionComponent = registerFunctionComponent((props) { /// return ['I am a function component', ...props.children]; /// }); /// ``` /// /// Example with display name: /// ``` -/// var myFunctionComponent = registerFunctionComponent((Map props) { +/// var myFunctionComponent = registerFunctionComponent((props) { /// return ['I am a function component', ...props.children]; /// }, displayName: 'myFunctionComponent'); /// ``` @@ -1501,802 +1520,598 @@ ComponentRegistrar2 registerComponent2 = validateJsApiThenReturn(() => registrat FunctionComponentRegistrar registerFunctionComponent = validateJsApiThenReturn(() => registration_utils.registerFunctionComponent); -/// The HTML `` [AnchorElement]. +/// The HTML `` `AnchorElement`. dynamic a = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('a')); -/// The HTML `` [Element]. +/// The HTML `` `Element`. dynamic abbr = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('abbr')); -/// The HTML `
    ` [Element]. +/// The HTML `
    ` `Element`. dynamic address = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('address')); -/// The HTML `` [AreaElement]. +/// The HTML `` `AreaElement`. dynamic area = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('area')); -/// The HTML `
    ` [Element]. +/// The HTML `
    ` `Element`. dynamic article = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('article')); -/// The HTML `
  • ` [Element]. +/// The HTML `` `Element`. dynamic col = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('col')); -/// The HTML `` [Element]. +/// The HTML `` `Element`. dynamic colgroup = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('colgroup')); -/// The HTML `` [Element]. +/// The HTML `` `Element`. dynamic data = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('data')); -/// The HTML `` [DataListElement]. +/// The HTML `` `DataListElement`. dynamic datalist = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('datalist')); -/// The HTML `
    ` [Element]. +/// The HTML `
    ` `Element`. dynamic dd = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('dd')); -/// The HTML `` [Element]. +/// The HTML `` `Element`. dynamic del = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('del')); -/// The HTML `
    ` [DetailsElement]. +/// The HTML `
    ` `DetailsElement`. dynamic details = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('details')); -/// The HTML `` [Element]. +/// The HTML `` `Element`. dynamic dfn = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('dfn')); -/// The HTML `` [DialogElement]. +/// The HTML `` `DialogElement`. dynamic dialog = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('dialog')); -/// The HTML `
    ` [DivElement]. +/// The HTML `
    ` `DivElement`. dynamic div = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('div')); -/// The HTML `
    ` [DListElement]. +/// The HTML `
    ` `DListElement`. dynamic dl = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('dl')); -/// The HTML `
    ` [Element]. +/// The HTML `
    ` `Element`. dynamic dt = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('dt')); -/// The HTML `` [Element]. +/// The HTML `` `Element`. dynamic em = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('em')); -/// The HTML `` [EmbedElement]. +/// The HTML `` `EmbedElement`. dynamic embed = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('embed')); -/// The HTML `
    ` [FieldSetElement]. +/// The HTML `
    ` `FieldSetElement`. dynamic fieldset = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('fieldset')); -/// The HTML `
    ` [Element]. +/// The HTML `
    ` `Element`. dynamic figcaption = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('figcaption')); -/// The HTML `
    ` [Element]. +/// The HTML `
    ` `Element`. dynamic figure = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('figure')); -/// The HTML `
    ` [Element]. +/// The HTML `` `Element`. dynamic caption = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('caption')); -/// The HTML `` [Element]. +/// The HTML `` `Element`. dynamic cite = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('cite')); -/// The HTML `` [Element]. +/// The HTML `` `Element`. dynamic code = validateJsApiThenReturn(() => ReactDomComponentFactoryProxy('code')); -/// The HTML `