Skip to content

Repository files navigation

Dart wrapper for React JS

PubReactJS v18.2.0Dart CIReact Dart API Docs

Thanks to the folks at Vacuumlabs for creating this project! ❤️

Getting Started

Installation

If you are not familiar with the ReactJS library, read this react tutorial first.

  1. Install the Dart SDK

    brew install dart
  2. Create a pubspec.yaml file in the root of your project, and add react as a dependency:

    name: your_package_nameversion: 1.0.0environment:
    sdk: ^2.11.0dependencies:
    react: ^6.0.0
  3. Install the dependencies using pub:

    dart pub get

Wire things up

HTML

In a .html file, include the javascript libraries (provided with this library for compatibility reasons) within your .html file, and also add an element with an id to mount your React component.

This package now supports both React 17 and React 18. To opt into React 18, replace usages of this package's JS files with their new, React 18 versions (see table below).

The React 17 JS files are now deprecated, and will be removed in the next major version of this package, 8.0.0.

React 18
ModeLibraryJS File Name
DevelopmentReact & ReactDOMpackages/react/js/react.dev.js
ProductionReact & ReactDOMpackages/react/js/react.min.js
React 17 (Deprecated)
ModeLibraryJS File Name
DevelopmentReactpackages/react/react.js
DevelopmentReactDOMpackages/react/react_dom.js
ProductionReact & ReactDOMpackages/react/react_with_react_dom_prod.js
ProductionReactpackages/react/react_prod.js
ProductionReactDOMpackages/react/react_dom_prod.js

Lastly, add the .js file that Dart will generate. The file will be the name of the .dart file that contains your main entrypoint, with .js at the end.

<html><head><!-- ... --></head><body><divid="react_mount_point">Here will be react content</div><scriptsrc="packages/react/js/react.dev.js"></script><scriptdefersrc="your_dart_file_name.dart.js"></script></body></html>

Note: When serving your application in production, use packages/react/js/react.min.js file instead of the un-minified react.dev.js shown in the example above.

Dart App

Once you have an .html file containing the necessary .js files, you can initialize React in the main entrypoint of your Dart application.

import'dart:html';
import'package:react/react.dart';
import'package:react/react_dom.dart'as react_dom;
main() {
// Something to render... in this case a simple <div> with no props, and a string as its children.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'));
}

Build Stuff

Using browser native elements

If you are familiar with React (without JSX extension) React-dart shouldn't surprise you much. All elements are defined as functions that take props as first argument and children as optional second argument. props should implement Map and children is either one React element or List with multiple elements.

var aDiv =div({"className":"something"}, [
h1({"style": {"height":"20px"}}, "Headline"),
a({"href":"something.com"}, "Something"),
"Some text"
]);

For event handlers you must provide function that takes a SyntheticEvent(defined in this library).

var aButton =button({"onClick": (SyntheticMouseEvent event) =>print(event)});

Defining custom components

  1. Define custom class that extends Component2 and implements - at a minimum - render.

    // cool_widget.dartimport'package:react/react.dart';
    classCoolWidgetComponentextendsComponent2 {
    render() =>div({}, "CoolWidgetComponent");
    }
  2. Then register the class so ReactJS can recognize it.

    varCoolWidget=registerComponent2(() =>CoolWidgetComponent());

    Warning:registerComponent2 should be called only once per component and lifetime of application.

  3. Then you can use the registered component similarly as native elements.

    // app.dartimport'dart:html';
    import'package:react/react.dart';
    import'package:react/react_dom.dart'as react_dom;
    import'cool_widget.dart';
    main() {
    react_dom.render(CoolWidget({}), querySelector('#react_mount_point'));
    }

Custom component with props

// cool_widget.dartimport'package:react/react.dart';
classCoolWidgetComponentextendsComponent2 {
@overriderender() {
returndiv({}, props['text']);
}
}
varCoolWidget=registerComponent2(() =>CoolWidgetComponent());
// app.dartimport'dart:html';
import'package:react/react.dart';
import'package:react/react_dom.dart'as react_dom;
import'cool_widget.dart';
main() {
react_dom.render(CoolWidget({"text":"Something"}), querySelector('#react_mount_point'));
}

Custom component with a typed interface

Note: The typed interface capabilities of this library are fairly limited, and can result in extremely verbose implementations. We strongly recommend using the OverReact package - which makes creating statically-typed React UI components using Dart easy.

// cool_widget.darttypedefCoolWidgetType({String headline, String text, int counter});
var_CoolWidget=registerComponent2(() =>CoolWidgetComponent());
CoolWidgetTypeCoolWidget({String headline, String text, int counter}) {
return_CoolWidget({'headline':headline, 'text':text});
}
classCoolWidgetComponentextendsComponent2 {
Stringget headline => props['headline'];
Stringget text => props['text'];
intget counter => props['counter'];
@overriderender() {
returndiv({},
h1({}, headline),
span({}, text),
span({}, counter),
);
}
}
// app.dartimport'dart:html';
import'package:react/react.dart';
import'package:react/react_dom.dart'as react_dom;
import'cool_widget.dart';
voidmain() {
react_dom.render(
myComponent(
headline:"My custom headline",
text:"My custom text",
counter:3,
),
querySelector('#react_mount_point')
);
}

React Component Lifecycle methods

The Component2 class mirrors ReactJS' React.Component class, and contains all the same methods.

See: ReactJS Lifecycle Method Documentation for more information.

classMyComponentextendsComponent2 {
@overridevoidcomponentWillMount() {}
@overridevoidcomponentDidMount() {}
@overridevoidcomponentWillReceiveProps(Map nextProps) {}
@overridevoidcomponentWillUpdate(Map nextProps, Map nextState) {}
@overridevoidcomponentDidUpdate(Map prevProps, Map prevState) {}
@overridevoidcomponentWillUnmount() {}
@overrideboolshouldComponentUpdate(Map nextProps, Map nextState) =>true;
@overrideMapgetInitialState() => {};
@overrideMapgetDefaultProps() => {};
@overriderender() =>div({}, props['text']);
}

Using refs and findDOMNode

The use of component refs in react-dart is a bit different from React JS.

  • You can specify a ref name in component props and then call ref method to get the referenced element.
  • Return values for Dart components, DOM components and JavaScript components are different.
    • For a Dart component, you get an instance of the Dart class of the component.
    • For primitive components (like DOM elements), you get the DOM node.
    • For JavaScript composite components, you get a ReactElement representing the react component.

If you want to work with DOM nodes of dart or JS components instead, you can call top level findDOMNode on anything the ref returns.

varDartComponent=registerComponent2(() =>_DartComponent());
class_DartComponentextendsComponent2 {
@overriderender() =>div({});
voidsomeInstanceMethod(int count) {
window.alert('count: $count');
}
}
varParentComponent=registerComponent2(() =>_ParentComponent());
class_ParentComponentextendsComponent2 {
final inputRef =createRef<InputElement>(); // inputRef.current is the DOM node.final dartComponentRef =createRef<_DartComponent>(); // dartComponentRef.current is the instance of _DartComponent@overridevoidcomponentDidMount() {
print(inputRef.current.value); // Prints "hello" to the console.
dartComponentRef.current.someInstanceMethod(5); // Calls the method defined in _DartComponent
react_dom.findDOMNode(dartComponentRef); // Returns div element rendered from _DartComponent
react_dom.findDOMNode(this); // Returns root dom element rendered from this component
}
@overriderender() {
returndiv({},
input({"ref": inputRef, "defaultValue":"hello"}),
DartComponent({"ref": dartComponentRef}),
);
}
}

Example Application

For more robust examples take a look at our examples.

Unit Testing Utilities

lib/react_test_utils.dart is a Dart wrapper for the ReactJS TestUtils library allowing for unit tests to be made for React components in Dart.

Here is an example of how to use package:react/react_test_utils.dart within a Dart test.

import'package:test/test.dart';
import'package:react/react.dart'as react;
import'package:react/react_dom.dart'as react_dom;
import'package:react/react_test_utils.dart'as react_test_utils;
classMyTestComponentextends react.Component2 {
@overrideMapgetInitialState() => {'text':'testing...'};
@overriderender() {
return react.div({},
react.button({'onClick': (_) =>setState({'text':'success'})}),
react.span({'className':'spanText'}, state['text']),
);
}
}
var myTestComponent = react.registerComponent2(() =>newMyTestComponent());
voidmain() {
test('should click button and set span text to "success"', () {
var component = react_test_utils.renderIntoDocument(myTestComponent({}));
// Find button using tag namevar buttonElement = react_test_utils.findRenderedDOMComponentWithTag(
component, 'button');
// Find span using class namevar spanElement = react_test_utils.findRenderedDOMComponentWithClass(
component, 'spanText');
var buttonNode = react_dom.findDOMNode(buttonElement);
var spanNode = react_dom.findDOMNode(spanElement);
// Span text should equal the initial stateexpect(spanNode.text, equals('testing...'));
// Click the button and trigger the onClick event
react_test_utils.Simulate.click(buttonNode);
// Span text should change to 'success'expect(spanNode.text, equals('success'));
});
}

Contributing

Format using

dart format -l 120 .

While we'd like to adhere to the recommended line length of 80, it's too short for much of the code repo written before a formatter was use, causing excessive wrapping and code that's hard to read.

So, we use a line length of 120 instead.

Running Tests

dart2js

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")

dart run build_runner test -- --preset dartdevc

NOTE: When using Dart SDK < 2.14.0, use --preset dartdevc-legacy instead.

Building React JS Source Files

Make sure the packages you need are dependencies in package.json then run:

yarn install

After modifying files any files in ./js_src/, run:

yarn run build

About

Dart Bindings for React JS

Topics

Resources

Stars

424 stars

Watchers

38 watching

Forks

Releases

Packages

Used by

Contributors

Languages