Skip to content

React 18.2.0 #365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 33 commits into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
582f969
add react 18 rc and other deps
aaronlademann-wf Apr 1, 2022
02068ca
more React 18 [wip]
aaronlademann-wf Apr 1, 2022
468aacd
Fix / reorganize tests, deprecate RTU
aaronlademann-wf Apr 4, 2022
232f67c
[wip] Add suspense
aaronlademann-wf Apr 4, 2022
6adf53a
[wip] Roll back to react-redux 7 for now
aaronlademann-wf Apr 6, 2022
9884640
Fix a few tests
aaronlademann-wf Apr 6, 2022
c774253
Merge remote-tracking branch 'origin/master' into react-18-rc-test
greglittlefield-wf Aug 10, 2023
480c91a
Upgrade to react 18.2.0
greglittlefield-wf Aug 10, 2023
9c513b3
Build JS with React 18.2.0
greglittlefield-wf Aug 10, 2023
d0b876e
Fix duplicate Suspense after merge
greglittlefield-wf Aug 10, 2023
040a2c4
Remove RTL references
greglittlefield-wf Aug 10, 2023
60cb3ae
Fix test template
greglittlefield-wf Aug 10, 2023
0730056
Reset test directory to master
greglittlefield-wf Aug 10, 2023
4a1b67c
Pin to same react-redux as master
greglittlefield-wf Aug 17, 2023
ffd819f
Update compiled assets
greglittlefield-wf Aug 17, 2023
35cff8e
Merge remote-tracking branch 'origin/master' into react-18-2-0
greglittlefield-wf Nov 7, 2023
09d0a68
Fix warnings
greglittlefield-wf Nov 7, 2023
ee3daeb
Merge branch 'master' of github.com:Workiva/react-dart into react-18-2-0
regenvanwalbeek-wf Feb 12, 2024
5a1005d
Logical merge conflict
regenvanwalbeek-wf Feb 12, 2024
664c652
Fix null safety compilation issues
greglittlefield-wf Feb 19, 2024
2119beb
Fix null safety compilation issues in examples
greglittlefield-wf Feb 19, 2024
da5e00c
Merge remote-tracking branch 'origin/master' into react-18-2-0
greglittlefield-wf Oct 18, 2024
74aa3dd
Fix test failures from unrelated react_dom.render deprecation errors
greglittlefield-wf Oct 18, 2024
7c4bed2
Deprecate calculateChangedBits and update tests for React 18
greglittlefield-wf Oct 18, 2024
fc2deca
Make args optional to fix dart2js failures
greglittlefield-wf Oct 18, 2024
954fca9
Format
greglittlefield-wf Oct 18, 2024
52f1a56
Add (failing) test for react_dom.render console.error silencing
greglittlefield-wf Jan 27, 2025
d38e155
Remove tests for pre-Dart-2.14 issue, up SDK constraint
greglittlefield-wf Jan 27, 2025
8674405
Add console.error wrapper to suppress ReactDOM.render errors
greglittlefield-wf Jan 27, 2025
8886413
Recompile JS assets
greglittlefield-wf Jan 27, 2025
0d36059
Remove unused parameter
greglittlefield-wf Jan 27, 2025
74d3a4d
Merge pull request #413 from Workiva/suppress-react-dom-render-warnings
btr-rmconsole-6[bot] Jan 29, 2025
ec60ac1
Merge branch 'master' of github.com:Workiva/react-dart into react-18-2-0
bender-wk Jan 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# top-most EditorConfig file
root = true

[*.dart]
max_line_length = 120

Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,14 @@ __New Features__
import 'some_widget.dart'; // Where your component is defined

main() {
final root = react_dom.createRoot(querySelector('#idOfSomeNodeInTheDom'));
final renderedWidget = SomeWidget({
// put some props here
}, [
// put some children here!
]);

react_dom.render(renderedWidget, querySelector('#idOfSomeNodeInTheDom'));
root.render(renderedWidget);
}
```

Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Dart wrapper for [React JS](https://reactjs.org/)

[![Pub](https://img.shields.io/pub/v/react.svg)](https://pub.dev/packages/react)
![ReactJS v17.0.1](https://img.shields.io/badge/React_JS-v17.0.1-green.svg)
![ReactJS v18.0.0](https://img.shields.io/badge/React_JS-v18.0.0-green.svg)
[![Dart CI](https://github.com/Workiva/react-dart/workflows/Dart%20CI/badge.svg?branch=master)](https://github.com/Workiva/react-dart/actions?query=workflow%3A%22Dart+CI%22+branch%3Amaster)
[![React Dart API Docs](https://img.shields.io/badge/api_docs-react-blue.svg)](https://pub.dev/documentation/react/latest/)

Expand Down Expand Up @@ -81,7 +81,8 @@ main() {
var component = div({}, "Hello world!");

// Render it into the mount node we created in our .html file.
react_dom.render(component, querySelector('#react_mount_point'));
final root = react_dom.createRoot(querySelector('#react_mount_point'));
root.render(component);
}
```

Expand Down Expand Up @@ -141,7 +142,8 @@ var aButton = button({"onClick": (SyntheticMouseEvent event) => print(event)});
import 'cool_widget.dart';

main() {
react_dom.render(CoolWidget({}), querySelector('#react_mount_point'));
final root = react_dom.createRoot(querySelector('#react_mount_point'));
root.render(CoolWidget({}));
}
```

Expand Down Expand Up @@ -173,7 +175,8 @@ import 'package:react/react_dom.dart' as react_dom;
import 'cool_widget.dart';

main() {
react_dom.render(CoolWidget({"text": "Something"}), querySelector('#react_mount_point'));
final root = react_dom.createRoot(querySelector('#react_mount_point'));
root.render(CoolWidget({"text": "Something"}));
}
```

Expand Down Expand Up @@ -221,13 +224,13 @@ import 'package:react/react_dom.dart' as react_dom;
import 'cool_widget.dart';

void main() {
react_dom.render(
final root = react_dom.createRoot(querySelector('#react_mount_point'));
root.render(
myComponent(
headline: "My custom headline",
text: "My custom text",
counter: 3,
),
querySelector('#react_mount_point')
)
);
}
```
Expand Down Expand Up @@ -375,7 +378,7 @@ void main() {
expect(spanNode.text, equals('testing...'));

// Click the button and trigger the onClick event
react_test_utils.Simulate.click(buttonNode);
react_dom.ReactTestUtils.act(buttonNode.click);

// Span text should change to 'success'
expect(spanNode.text, equals('success'));
Expand Down Expand Up @@ -404,8 +407,6 @@ So, we use a line length of 120 instead.
dart run build_runner test --release -- --preset dart2js
```

> NOTE: When using Dart SDK < 2.14.0, use `--preset dart2js-legacy` instead.

#### Dart Dev Compiler ("DDC")

```bash
Expand Down
19 changes: 19 additions & 0 deletions build.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
targets:
$default:
builders:
test_html_builder:
options:
templates:
"test/js_builds/templates/js_dev.html":
- "test/js_builds/js_dev_test.dart"
"test/js_builds/templates/js_dev_with_addons.html":
- "test/js_builds/js_dev_with_addons_test.dart"
"test/js_builds/templates/js_prod_combined.html":
- "test/js_builds/js_prod_combined_test.dart"
"test/js_builds/templates/js_prod.html":
- "test/js_builds/js_prod_test.dart"
"test/factory/_factory_test_template.html":
- "test/factory/**_test.dart"
"test/lifecycle/_react_lifecycle_test_template.html":
- "test/lifecycle/**_test.dart"
"test/react_client/_react_client_test_template.html":
- "test/react_client/**_test.dart"
"test/_react_test_template.html":
- "test/*_test.dart"
mockito:mockBuilder:
# Scope only to files declaring mocks, for performance.
generate_for:
Expand Down
10 changes: 2 additions & 8 deletions dart_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,11 @@ platforms:
concurrency: 1

presets:
dart2js-legacy:
exclude_tags: no-dart2js

dartdevc-legacy:
exclude_tags: no-dartdevc

dart2js:
exclude_tags: "no-dart2js || no-sdk-2-14-plus"
exclude_tags: no-dart2js

dartdevc:
exclude_tags: "no-dartdevc || no-sdk-2-14-plus"
exclude_tags: no-dartdevc

tags:
# Variadic children tests of >5 children that fail in Dart 2.7 for an unknown reason, seemingly an SDK bug.
Expand Down
48 changes: 24 additions & 24 deletions example/geocodes/geocodes.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// ignore_for_file: deprecated_member_use_from_same_package
import 'dart:async';
import 'dart:convert';
import 'dart:html';
Expand Down Expand Up @@ -26,7 +25,7 @@ import 'package:react/react_dom.dart' as react_dom;
/// This is the first custom `Component`.
///
/// It is just an HTML `<tr>` element displaying a single API response to the user.
class _GeocodesResultItem extends react.Component {
class _GeocodesResultItem extends react.Component2 {
/// The only function you must implement in the custom component is [render].
///
/// Every `Component` has a map of properties called `props`. It can be specified during creation.
Expand All @@ -46,11 +45,11 @@ class _GeocodesResultItem extends react.Component {
/// shortly.
///
/// This is the only correct way to create a `Component`. Do not use the constructor!
var geocodesResultItem = react.registerComponent(() => _GeocodesResultItem());
var GeocodesResultItem = react.registerComponent2(() => _GeocodesResultItem());

/// In this component we'll build an HTML `<table>` element full of the `<tr>` elements generated by
/// [_GeocodesResultItem]
class _GeocodesResultList extends react.Component {
class _GeocodesResultList extends react.Component2 {
@override
render() {
// Built-in HTML DOM components also have props - which correspond to HTML element attributes.
Expand Down Expand Up @@ -81,7 +80,7 @@ class _GeocodesResultList extends react.Component {
// The second argument contains the body of the component (as you have already seen).
//
// It can be a String, a Component or an Iterable.
props['data'].map((item) => geocodesResultItem({
props['data'].map((item) => GeocodesResultItem({
'key': item['formatted_address'],
'lat': item['geometry']['location']['lat'],
'lng': item['geometry']['location']['lng'],
Expand All @@ -93,7 +92,7 @@ class _GeocodesResultList extends react.Component {
}
}

var geocodesResultList = react.registerComponent(() => _GeocodesResultList());
var GeocodesResultList = react.registerComponent2(() => _GeocodesResultList());

/// In this `Component` we'll build a search form.
///
Expand All @@ -102,11 +101,11 @@ var geocodesResultList = react.registerComponent(() => _GeocodesResultList());
/// > The functions can be `Component` parameters _(handy for callbacks)_
///
/// > The DOM [Element]s can be accessed using `ref`s.
class _GeocodesForm extends react.Component {
var searchInputInstance;
class _GeocodesForm extends react.Component2 {
final searchInputRef = react.createRef<InputElement>();

@override
getInitialState() => {
get initialState => {
'value': '',
};

Expand Down Expand Up @@ -134,7 +133,7 @@ class _GeocodesForm extends react.Component {
'value': state['value'],
'onChange': handleChange,
// Input is referenced to access it's value
'ref': (searchInputInstance) => this.searchInputInstance = searchInputInstance,
'ref': searchInputRef,
}),
react.span({
'key': 'spacer',
Expand All @@ -156,7 +155,7 @@ class _GeocodesForm extends react.Component {
/// Handle form submission via `props.onSubmit`
onFormSubmit(react.SyntheticEvent event) {
event.preventDefault();
final inputElement = react_dom.findDOMNode(searchInputInstance);
final inputElement = searchInputRef.current!;
// The input's value is accessed.
final address = inputElement.value;
inputElement.value = '';
Expand All @@ -165,10 +164,10 @@ class _GeocodesForm extends react.Component {
}
}

var geocodesForm = react.registerComponent(() => _GeocodesForm());
var GeocodesForm = react.registerComponent2(() => _GeocodesForm());

/// Renders an HTML `<li>` to be used as a child within the [_GeocodesHistoryList].
class _GeocodesHistoryItem extends react.Component {
class _GeocodesHistoryItem extends react.Component2 {
reload(e) {
props['reloader'](props['query']);
}
Expand All @@ -187,12 +186,12 @@ class _GeocodesHistoryItem extends react.Component {
}
}

var geocodesHistoryItem = react.registerComponent(() => _GeocodesHistoryItem());
var GeocodesHistoryItem = react.registerComponent2(() => _GeocodesHistoryItem());

/// Renders the "history list"
///
/// NOTE: It just passes the callback from the parent.
class _GeocodesHistoryList extends react.Component {
class _GeocodesHistoryList extends react.Component2 {
@override
render() {
return react.div({}, [
Expand All @@ -201,7 +200,7 @@ class _GeocodesHistoryList extends react.Component {
{
'key': 'list',
},
List.from((props['data'] as Map).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'],
Expand All @@ -212,7 +211,7 @@ class _GeocodesHistoryList extends react.Component {
}
}

var geocodesHistoryList = react.registerComponent(() => _GeocodesHistoryList());
var GeocodesHistoryList = react.registerComponent2(() => _GeocodesHistoryList());

/// The root `Component` of our application.
///
Expand All @@ -232,9 +231,9 @@ var geocodesHistoryList = react.registerComponent(() => _GeocodesHistoryList());
///
/// When the request is sent, it has `pending` status in the history. This changes to `OK` or `error` when the answer
/// _(or timeout)_ comes. If the new request is sent meanwhile, the old one is cancelled.
class _GeocodesApp extends react.Component {
class _GeocodesApp extends react.Component2 {
@override
getInitialState() => {
get initialState => {
'shown_addresses': [], // Data from last query.
'history': {} // Map of past queries.
};
Expand Down Expand Up @@ -302,17 +301,17 @@ class _GeocodesApp extends react.Component {
render() {
return react.div({}, [
react.h1({'key': '1'}, 'Geocode resolver'),
geocodesResultList({
GeocodesResultList({
'key': '2',
// The state values are passed to the children as the properties.
'data': state['shown_addresses']
}),
geocodesForm({
GeocodesForm({
'key': '3',
// `newQuery` is the final callback of the button click.
'submitter': newQuery
}),
geocodesHistoryList({
GeocodesHistoryList({
'key': '4',
'data': state['history'],
// `newQuery` is the final callback of the button click.
Expand All @@ -322,11 +321,12 @@ class _GeocodesApp extends react.Component {
}
}

var geocodesApp = react.registerComponent(() => _GeocodesApp());
var GeocodesApp = react.registerComponent2(() => _GeocodesApp());

/// And finally, a few magic commands to wire it all up!
///
/// Select the root of the app and the place in the DOM where it should be mounted.
void main() {
react_dom.render(geocodesApp({}), querySelector('#content'));
final root = react_dom.createRoot(querySelector('#content')!);
root.render(GeocodesApp({}));
}
8 changes: 5 additions & 3 deletions example/js_components/js_components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import 'dart:html';
import 'package:js/js.dart';
import 'package:react/react.dart' as react;
import 'package:react/react_client.dart';
import 'package:react/react_client/react_interop.dart';
import 'package:react/react_client/react_interop.dart' show ReactClass;
import 'package:react/react_dom.dart' as react_dom;

main() {
final content = IndexComponent({});

react_dom.render(content, querySelector('#content'));
final root = react_dom.createRoot(querySelector('#content')!);

root.render(react.StrictMode({}, content));
}

var IndexComponent = react.registerComponent2(() => _IndexComponent());
Expand Down Expand Up @@ -104,7 +106,7 @@ final SimpleCustom = ReactJsComponentFactoryProxy(_SimpleCustomComponent);

/// JS interop wrapper class for the component,
/// allowing us to interact with component instances
/// made available via refs or [react_dom.render] calls.
/// made available via refs or render calls.
///
/// This is optional, as you won't always need to access the component's API.
@JS('_SimpleCustomComponent')
Expand Down
2 changes: 1 addition & 1 deletion example/suspense/suspense.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import './simple_component.dart' deferred as simple;
main() {
final content = wrapper({});

react_dom.render(content, querySelector('#content'));
react_dom.render(content, querySelector('#content')!);
}

final lazyComponent = react.lazy(() async {
Expand Down
Loading