Skip to content

Commit 40b9ef2

Browse files
committed
refactor displayName and add tests
1 parent 1c89e35 commit 40b9ef2

File tree

3 files changed

+59
-30
lines changed

3 files changed

+59
-30
lines changed

lib/react_client.dart

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -457,39 +457,43 @@ class ReactDartFunctionComponentFactoryProxy extends ReactComponentFactoryProxy
457457
/// The React JS component definition of this Function Component.
458458
final JsFunctionComponent reactFunction;
459459

460-
ReactDartFunctionComponentFactoryProxy(this.reactFunction, [this.displayName]);
460+
ReactDartFunctionComponentFactoryProxy(DartFunctionComponent dartFunctionComponent, {String displayName})
461+
: this.displayName = displayName ?? _getJsFunctionName(dartFunctionComponent),
462+
this.reactFunction = _wrapFunctionComponent(dartFunctionComponent,
463+
displayName: displayName ?? _getJsFunctionName(dartFunctionComponent));
461464

462465
@override
463466
JsFunctionComponent get type => reactFunction;
464-
}
465467

466-
/// Creates a function component from the given [dartFunctionComponent] that can be used with React.
467-
///
468-
/// [displayName] Sets the component name for debugging purposes.
469-
///
470-
/// In DDC, this will be the [DartFunctionComponent] name, but in dart2js it will be null unless
471-
/// overridden, since using runtimeType can lead to larger dart2js output.
472-
///
473-
/// This will result in the dart2js name being `ReactDartComponent2` (the
474-
/// name of the proxying JS component defined in _dart_helpers.js).
475-
JsFunctionComponent _wrapFunctionComponent(DartFunctionComponent dartFunctionComponent, {String displayName}) {
476-
displayName ??= getProperty(dartFunctionComponent, 'name') ?? getProperty(dartFunctionComponent, '\$static_name');
477-
478-
// dart2js uses null and undefined interchangeably, meaning returning `null` from dart
479-
// may show up in js as `undefined`, ReactJS doesnt like that and expects a js `null` to be returned,
480-
// and throws if it gets `undefined`. `jsNull` is an interop variable that holds a JS `null` value
481-
// to force `null` as the return value if user returns a Dart `null`.
482-
// See: https://github.com/dart-lang/sdk/issues/27485
483-
jsFunctionComponent(JsMap jsProps, [JsMap _legacyContext]) =>
484-
dartFunctionComponent(JsBackedMap.backedBy(jsProps)) ?? jsNull;
485-
JsFunctionComponent interopFunction = allowInterop(jsFunctionComponent);
486-
if (displayName != null) {
487-
// This is a work-around to display the correct name in the React DevTools.
488-
_defineProperty(interopFunction, 'name', jsify({'value': displayName}));
468+
static String _getJsFunctionName(Function object) =>
469+
getProperty(object, 'name') ?? getProperty(object, '\$static_name');
470+
471+
/// Creates a function component from the given [dartFunctionComponent] that can be used with React.
472+
///
473+
/// [displayName] Sets the component name for debugging purposes.
474+
///
475+
/// In DDC, this will be the [DartFunctionComponent] name, but in dart2js it will be null unless
476+
/// overridden, since using runtimeType can lead to larger dart2js output.
477+
///
478+
/// This will result in the dart2js name being `ReactDartComponent2` (the
479+
/// name of the proxying JS component defined in _dart_helpers.js).
480+
static JsFunctionComponent _wrapFunctionComponent(DartFunctionComponent dartFunctionComponent, {String displayName}) {
481+
// dart2js uses null and undefined interchangeably, meaning returning `null` from dart
482+
// may show up in js as `undefined`, ReactJS doesnt like that and expects a js `null` to be returned,
483+
// and throws if it gets `undefined`. `jsNull` is an interop variable that holds a JS `null` value
484+
// to force `null` as the return value if user returns a Dart `null`.
485+
// See: https://github.com/dart-lang/sdk/issues/27485
486+
jsFunctionComponent(JsMap jsProps, [JsMap _legacyContext]) =>
487+
dartFunctionComponent(JsBackedMap.backedBy(jsProps)) ?? jsNull;
488+
JsFunctionComponent interopFunction = allowInterop(jsFunctionComponent);
489+
if (displayName != null) {
490+
// This is a work-around to display the correct name in the React DevTools.
491+
_defineProperty(interopFunction, 'name', jsify({'value': displayName}));
492+
}
493+
// ignore: invalid_use_of_protected_member
494+
setProperty(interopFunction, 'dartComponentVersion', ReactDartComponentVersion.component2);
495+
return interopFunction;
489496
}
490-
// ignore: invalid_use_of_protected_member
491-
setProperty(interopFunction, 'dartComponentVersion', ReactDartComponentVersion.component2);
492-
return interopFunction;
493497
}
494498

495499
/// Converts a list of variadic children arguments to children that should be passed to ReactJS.
@@ -996,7 +1000,7 @@ ReactDartComponentFactoryProxy2 _registerComponent2(
9961000
/// which produces a new `JsFunctionComponent`.
9971001
ReactDartFunctionComponentFactoryProxy _registerFunctionComponent(DartFunctionComponent dartFunctionComponent,
9981002
{String displayName}) =>
999-
ReactDartFunctionComponentFactoryProxy(_wrapFunctionComponent(dartFunctionComponent, displayName: displayName));
1003+
ReactDartFunctionComponentFactoryProxy(dartFunctionComponent, displayName: displayName);
10001004

10011005
/// A mapping from converted/wrapped JS handler functions (the result of [_convertEventHandlers])
10021006
/// to the original Dart functions (the input of [_convertEventHandlers]).

test/factory/dart_function_factory_test.dart

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// ignore_for_file: deprecated_member_use_from_same_package
22
// ignore_for_file: invalid_use_of_protected_member
3+
import 'package:js/js_util.dart';
34
@TestOn('browser')
4-
55
import 'package:test/test.dart';
66
import 'package:react/react.dart' as react;
77
import 'package:react/react_client.dart';
@@ -19,10 +19,32 @@ main() {
1919
group('- common factory behavior -', () {
2020
commonFactoryTests(FunctionFoo, isFunctionComponent: true);
2121
});
22+
23+
group('displayName', () {
24+
test('gets automaticly populated when not provided', () {
25+
expect(FunctionFoo.displayName, '_FunctionFoo');
26+
27+
expect(_getJsFunctionName(FunctionFoo.reactFunction), '_FunctionFoo');
28+
29+
expect(FunctionFoo.displayName, _getJsFunctionName(FunctionFoo.reactFunction));
30+
});
31+
32+
test('is populated by the provided argument', () {
33+
expect(NamedFunctionFoo.displayName, 'Bar');
34+
35+
expect(_getJsFunctionName(NamedFunctionFoo.reactFunction), 'Bar');
36+
37+
expect(NamedFunctionFoo.displayName, _getJsFunctionName(NamedFunctionFoo.reactFunction));
38+
});
39+
});
2240
});
2341
});
2442
}
2543

44+
String _getJsFunctionName(Function object) => getProperty(object, 'name') ?? getProperty(object, '\$static_name');
45+
46+
final NamedFunctionFoo = react.registerFunctionComponent(_FunctionFoo, displayName: 'Bar');
47+
2648
final FunctionFoo = react.registerFunctionComponent(_FunctionFoo);
2749

2850
_FunctionFoo(Map props) {

test/util_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,23 @@ void main() {
2525
expect(isDartComponent2(JsFoo({})), isFalse);
2626
expect(isDartComponent2(Foo({})), isFalse);
2727
expect(isDartComponent2(Foo2({})), isTrue);
28+
expect(isDartComponent2(FunctionFoo({})), isTrue);
2829
});
2930

3031
test('isDartComponent1', () {
3132
expect(isDartComponent1(react.div({})), isFalse);
3233
expect(isDartComponent1(JsFoo({})), isFalse);
3334
expect(isDartComponent1(Foo({})), isTrue);
3435
expect(isDartComponent1(Foo2({})), isFalse);
36+
expect(isDartComponent1(FunctionFoo({})), isFalse);
3537
});
3638

3739
test('isDartComponent', () {
3840
expect(isDartComponent(react.div({})), isFalse);
3941
expect(isDartComponent(JsFoo({})), isFalse);
4042
expect(isDartComponent(Foo({})), isTrue);
4143
expect(isDartComponent(Foo2({})), isTrue);
44+
expect(isDartComponent(FunctionFoo({})), isTrue);
4245
});
4346
});
4447
}

0 commit comments

Comments
 (0)