https://github.com/Workiva/react-dart
Dart Bindings for React JS
https://github.com/Workiva/react-dart
dart dart-wrapper javascript react-js reactjs
Last synced: 5 months ago
JSON representation
Dart Bindings for React JS
- Host: GitHub
- URL: https://github.com/Workiva/react-dart
- Owner: Workiva
- License: bsd-2-clause
- Created: 2013-10-18T09:40:45.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2024-11-04T01:43:53.000Z (6 months ago)
- Last Synced: 2024-11-15T05:54:25.639Z (5 months ago)
- Topics: dart, dart-wrapper, javascript, react-js, reactjs
- Language: JavaScript
- Homepage:
- Size: 23 MB
- Stars: 413
- Watchers: 39
- Forks: 67
- Open Issues: 23
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Authors: AUTHORS
Awesome Lists containing this project
README
# Dart wrapper for [React JS](https://reactjs.org/)
[](https://pub.dev/packages/react)

[](https://github.com/Workiva/react-dart/actions?query=workflow%3A%22Dart+CI%22+branch%3Amaster)
[](https://pub.dev/documentation/react/latest/)_Thanks to the folks at [Vacuumlabs](https://www.vacuumlabs.com/) for creating this project! :heart:_
## Getting Started
### Installation
If you are not familiar with the ReactJS library, read this [react tutorial](https://reactjs.org/docs/getting-started.html) first.
1. Install the Dart SDK
```bash
brew install dart
```2. Create a `pubspec.yaml` file in the root of your project, and add `react` as a dependency:
```yaml
name: your_package_name
version: 1.0.0
environment:
sdk: ^2.11.0
dependencies:
react: ^6.0.0
```3. Install the dependencies using pub:
```bash
dart pub get
```### Wire things up
#### HTML
In a `.html` file, include the native javascript `react` and `react_dom` 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.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
Here will be react content
```
> __Note:__ When serving your application in production, use `packages/react/react_with_react_dom_prod.js`
file instead of the un-minified `react.js` / `react_dom.js` files 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.```dart
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 simplewith 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.```dart
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)_.
```dart
var aButton = button({"onClick": (SyntheticMouseEvent event) => print(event)});
```### Defining custom components
1. Define custom class that extends Component2 and implements - at a minimum - `render`.
```dart
// cool_widget.dartimport 'package:react/react.dart';
class CoolWidgetComponent extends Component2 {
render() => div({}, "CoolWidgetComponent");
}
```2. Then register the class so ReactJS can recognize it.
```dart
var CoolWidget = 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.
```dart
// 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
```dart
// cool_widget.dartimport 'package:react/react.dart';
class CoolWidgetComponent extends Component2 {
@override
render() {
return div({}, props['text']);
}
}var CoolWidget = registerComponent2(() => CoolWidgetComponent());
``````dart
// 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](https://pub.dev/packages/over_react) package - which
makes creating statically-typed React UI components using Dart easy.```dart
// cool_widget.dart
typedef CoolWidgetType({String headline, String text, int counter});var _CoolWidget = registerComponent2(() => CoolWidgetComponent());
CoolWidgetType CoolWidget({String headline, String text, int counter}) {
return _CoolWidget({'headline':headline, 'text':text});
}class CoolWidgetComponent extends Component2 {
String get headline => props['headline'];
String get text => props['text'];
int get counter => props['counter'];@override
render() {
return div({},
h1({}, headline),
span({}, text),
span({}, counter),
);
}
}
``````dart
// app.dartimport 'dart:html';
import 'package:react/react.dart';
import 'package:react/react_dom.dart' as react_dom;import 'cool_widget.dart';
void main() {
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](https://reactjs.org/docs/react-component.html) for more information.
```dart
class MyComponent extends Component2 {
@override
void componentWillMount() {}@override
void componentDidMount() {}@override
void componentWillReceiveProps(Map nextProps) {}@override
void componentWillUpdate(Map nextProps, Map nextState) {}@override
void componentDidUpdate(Map prevProps, Map prevState) {}@override
void componentWillUnmount() {}@override
bool shouldComponentUpdate(Map nextProps, Map nextState) => true;@override
Map getInitialState() => {};@override
Map getDefaultProps() => {};@override
render() => div({}, props['text']);
}
```#### Using refs and findDOMNode
The use of component `ref`s 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.```dart
var DartComponent = registerComponent2(() => _DartComponent());
class _DartComponent extends Component2 {
@override
render() => div({});void someInstanceMethod(int count) {
window.alert('count: $count');
}
}var ParentComponent = registerComponent2(() => _ParentComponent());
class _ParentComponent extends Component2 {
final inputRef = createRef(); // inputRef.current is the DOM node.
final dartComponentRef = createRef<_DartComponent>(); // dartComponentRef.current is the instance of _DartComponent@override
void componentDidMount() {
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 _DartComponentreact_dom.findDOMNode(this); // Returns root dom element rendered from this component
}@override
render() {
return div({},
input({"ref": inputRef, "defaultValue": "hello"}),
DartComponent({"ref": dartComponentRef}),
);
}
}
```### Example Application
For more robust examples take a look at our [examples](https://github.com/Workiva/react-dart/tree/master/example).
## Unit Testing Utilities
[lib/react_test_utils.dart](https://github.com/Workiva/react-dart/blob/master/lib/react_test_utils.dart) is a
Dart wrapper for the [ReactJS TestUtils](https://reactjs.org/docs/test-utils.html) 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.
```dart
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;class MyTestComponent extends react.Component2 {
@override
Map getInitialState() => {'text': 'testing...'};@override
render() {
return react.div({},
react.button({'onClick': (_) => setState({'text': 'success'})}),
react.span({'className': 'spanText'}, state['text']),
);
}
}var myTestComponent = react.registerComponent2(() => new MyTestComponent());
void main() {
test('should click button and set span text to "success"', () {
var component = react_test_utils.renderIntoDocument(myTestComponent({}));// Find button using tag name
var buttonElement = react_test_utils.findRenderedDOMComponentWithTag(
component, 'button');// Find span using class name
var 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 state
expect(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
```bash
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
```bash
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
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:
```bash
yarn install
```After modifying files any files in ./js_src/, run:
```bash
yarn run build
```