Skip to content

Commit 84530cd

Browse files
Merge pull request #135 from johnbland-wf/context
Context support
2 parents f0ac589 + 3602963 commit 84530cd

19 files changed

+809
-156
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,17 @@ void main() {
256256
```
257257

258258
To test the Dart wrapper, take a look at [test/react_test_utils_test.dart](test).
259+
260+
## Contributing
261+
262+
### Running Tests
263+
264+
Dart VM: `pub run test -p content-shell`
265+
dart2js: `pub run test -p chrome`
266+
267+
### Build JS
268+
269+
After modifying dart_helpers.js, run:
270+
```
271+
$ tool/build_js.sh
272+
```

example/test/context_test.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import 'dart:html';
2+
3+
import 'package:react/react_dom.dart' as react_dom;
4+
import 'package:react/react_client.dart';
5+
6+
import 'react_test_components.dart';
7+
8+
void main() {
9+
setClientConfiguration();
10+
11+
react_dom.render(contextComponent({},
12+
contextConsumerComponent({}),
13+
), querySelector('#content'));
14+
15+
react_dom.render(contextComponent({},
16+
contextConsumerComponent({}),
17+
), querySelector('#content'));
18+
19+
react_dom.render(contextComponent({},
20+
contextConsumerComponent({}, grandchildContextConsumerComponent({})),
21+
), querySelector('#content'));
22+
}

example/test/context_test.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
3+
<html>
4+
<head>
5+
<title>context_test</title>
6+
</head>
7+
<body>
8+
<div id="content"></div>
9+
<script src="packages/react/react.js"></script>
10+
<script src="packages/react/react_dom.js"></script>
11+
<script type="application/dart" src="context_test.dart"></script>
12+
<script src="packages/browser/dart.js"></script>
13+
</body>
14+
</html>

example/test/get_dom_node_test.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class _ChildComponent extends react.Component {
2020
react.div({}, [
2121
"Test element",
2222
counter.toString(),
23-
react.button({"onClick": (_) { counter++;redraw();} }, "Increase counter")
23+
react.button({'key': 'button', "onClick": (_) { counter++;redraw();} }, "Increase counter")
2424
]);
2525
}
2626

@@ -40,12 +40,12 @@ class SimpleComponent extends react.Component {
4040

4141
render() =>
4242
react.div({}, [
43-
react.span({"ref": "refToSpan"}, "Test"),
44-
react.span({}, counter),
45-
react.button({"onClick": (_) => (react_dom.findDOMNode(this) as HtmlElement).children.first.text = (++counter).toString()},"Increase counter"),
46-
react.br({}),
47-
ChildComponent({"ref": "refToElement"}),
48-
react.button({"onClick": (_) => window.alert((this.ref('refToElement') as _ChildComponent).counter.toString())}, "Show value of child element"),
43+
react.span({'key': 'span1', "ref": "refToSpan"}, "Test"),
44+
react.span({'key': 'span2'}, counter),
45+
react.button({'key': 'button1', "onClick": (_) => (react_dom.findDOMNode(this) as HtmlElement).children.first.text = (++counter).toString()},"Increase counter"),
46+
react.br({'key': 'br'}),
47+
ChildComponent({'key': 'child', "ref": "refToElement"}),
48+
react.button({'key': 'button2', "onClick": (_) => window.alert((this.ref('refToElement') as _ChildComponent).counter.toString())}, "Show value of child element"),
4949
]);
5050
}
5151

example/test/react_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import "react_test_components.dart";
88
void main() {
99
setClientConfiguration();
1010
react_dom.render(mainComponent({}, [
11-
helloGreeter({}, []),
12-
listComponent({}, []),
11+
helloGreeter({'key': 'hello'}, []),
12+
listComponent({'key': 'list'}, []),
1313
//clockComponent({"name": 'my-clock'}, []),
14-
checkBoxComponent({}, [])
14+
checkBoxComponent({'key': 'checkbox'}, [])
1515
]
1616
), querySelector('#content'));
1717
}

example/test/react_test_components.dart

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ class _HelloGreeter extends react.Component {
3030

3131
render() {
3232
return react.div({}, [
33-
react.input({'ref': 'myInput', 'value': bind('name'), 'onChange': onInputChange}),
34-
helloComponent({'name': state['name']})
33+
react.input({'key': 'input', 'ref': 'myInput', 'value': bind('name'), 'onChange': onInputChange}),
34+
helloComponent({'key': 'hello', 'name': state['name']})
3535
]);
3636
}
3737
}
@@ -47,8 +47,8 @@ class _CheckBoxComponent extends react.Component {
4747

4848
render() {
4949
return react.div({}, [
50-
react.label({'className': this.state["checked"] ? 'striked' : 'not-striked'}, 'do the dishes'),
51-
react.input({'type': 'checkbox', 'value': bind('checked')}, [])
50+
react.label({'key': 'label', 'className': this.state["checked"] ? 'striked' : 'not-striked'}, 'do the dishes'),
51+
react.input({'key': 'input', 'type': 'checkbox', 'value': bind('checked')})
5252
]);
5353
}
5454
}
@@ -136,8 +136,8 @@ class _ListComponent extends react.Component {
136136
}
137137

138138
return react.div({}, [
139-
react.button({"onClick": addItem}, "addItem"),
140-
react.ul({}, items),
139+
react.button({"onClick": addItem, 'key': 'button'}, "addItem"),
140+
react.ul({'key': 'list'}, items),
141141
]);
142142
}
143143
}
@@ -152,3 +152,61 @@ class _MainComponent extends react.Component {
152152
}
153153

154154
var mainComponent = react.registerComponent(() => new _MainComponent());
155+
156+
class _ContextComponent extends react.Component {
157+
@override
158+
Iterable<String> get childContextKeys => const ['foo', 'bar', 'renderCount'];
159+
160+
@override
161+
Map<String, dynamic> getChildContext() => {
162+
'foo': {'object': 'with value'},
163+
'bar': true,
164+
'renderCount': this.state['renderCount']
165+
};
166+
167+
render() {
168+
return react.ul({},
169+
react.button({'onClick': _onButtonClick}, 'Redraw'),
170+
react.br({}),
171+
'ContextComponent.getChildContext(): ',
172+
getChildContext().toString(),
173+
react.br({}),
174+
react.br({}),
175+
props['children']
176+
);
177+
}
178+
179+
_onButtonClick(event) {
180+
this.setState({'renderCount': (this.state['renderCount'] ?? 0) + 1});
181+
}
182+
}
183+
var contextComponent = react.registerComponent(() => new _ContextComponent());
184+
185+
class _ContextConsumerComponent extends react.Component {
186+
@override
187+
Iterable<String> get contextKeys => const ['foo'];
188+
189+
render() {
190+
return react.ul({},
191+
'ContextConsumerComponent.context: ',
192+
context.toString(),
193+
react.br({}),
194+
react.br({}),
195+
props['children']
196+
);
197+
}
198+
}
199+
var contextConsumerComponent = react.registerComponent(() => new _ContextConsumerComponent());
200+
201+
class _GrandchildContextConsumerComponent extends react.Component {
202+
@override
203+
Iterable<String> get contextKeys => const ['renderCount'];
204+
205+
render() {
206+
return react.ul({},
207+
'GrandchildContextConsumerComponent.context: ',
208+
context.toString(),
209+
);
210+
}
211+
}
212+
var grandchildContextConsumerComponent = react.registerComponent(() => new _GrandchildContextConsumerComponent());

example/test/ref_test.dart

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,23 @@ class _ParentComponent extends react.Component {
4545

4646
render() =>
4747
react.div({},[
48-
react.h1({}, "String refs"),
49-
react.h4({}, "<input>"),
50-
react.input({"ref": "inputRef"}),
51-
react.button({"onClick": showInputValue}, "Print input element value"),
52-
react.h4({}, "ChildComponent"),
53-
ChildComponent({"ref": "childRef"}),
54-
react.button({"onClick": showChildValue}, "Print child value"),
55-
react.button({"onClick": incrementChildValue}, "Increment child value"),
48+
react.h1({'key': 'string-h1'}, "String refs"),
49+
react.h4({'key': 'string-h4'}, "<input>"),
50+
react.input({'key': 'string-input', "ref": "inputRef"}),
51+
react.button({'key': 'string-show-input', "onClick": showInputValue}, "Print input element value"),
52+
react.h4({'key': 'string-h4-child'}, "ChildComponent"),
53+
ChildComponent({'key': 'string-child', "ref": "childRef"}),
54+
react.button({'key': 'string-show-button', "onClick": showChildValue}, "Print child value"),
55+
react.button({'key': 'string-increment-button', "onClick": incrementChildValue}, "Increment child value"),
5656

57-
react.h1({}, "Callback refs"),
58-
react.h4({}, "<input>"),
59-
react.input({"ref": (instance) => _inputCallbackRef = instance}),
60-
react.button({"onClick": showInputCallbackRefValue}, "Print input element value"),
61-
react.h4({}, "ChildComponent"),
62-
ChildComponent({"ref": (instance) => _childCallbackRef = instance}),
63-
react.button({"onClick": showChildCallbackRefValue}, "Print child value"),
64-
react.button({"onClick": incrementChildCallbackRefValue}, "Increment child value"),
57+
react.h1({'key': 'h1-callback'}, "Callback refs"),
58+
react.h4({'key': 'h4-callback-input'}, "<input>"),
59+
react.input({'key': 'callback-input', "ref": (instance) => _inputCallbackRef = instance}),
60+
react.button({'key': 'callback-show-input', "onClick": showInputCallbackRefValue}, "Print input element value"),
61+
react.h4({'key': 'callback-child-h4'}, "ChildComponent"),
62+
ChildComponent({'key': 'callback-child', "ref": (instance) => _childCallbackRef = instance}),
63+
react.button({'key': 'callback-show-button', "onClick": showChildCallbackRefValue}, "Print child value"),
64+
react.button({'key': 'callback-increment-button', "onClick": incrementChildCallbackRefValue}, "Increment child value"),
6565
]);
6666
}
6767

example/test/speed_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ class _Hello extends react.Component {
5656
for(var elem in data){
5757
children.add(
5858
react.div({'key': elem[0]},[
59-
react.span({}, elem[0]),
59+
react.span({'key': 'span1'}, elem[0]),
6060
" ",
61-
react.span({}, elem[1])
61+
react.span({'key': 'span2'}, elem[1])
6262
])
6363
);
6464
}

js_src/dart_helpers.js

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
function _getProperty(obj, key) { return obj[key]; }
66
function _setProperty(obj, key, value) { return obj[key] = value; }
77

8-
function _createReactDartComponentClassConfig(dartInteropStatics, componentStatics) {
9-
return {
8+
function _createReactDartComponentClassConfig(dartInteropStatics, componentStatics, jsConfig) {
9+
var config = {
1010
getInitialState: function() {
11-
this.dartComponent = dartInteropStatics.initComponent(this, this.props.internal, componentStatics);
11+
this.dartComponent = dartInteropStatics.initComponent(this, this.props.internal, this.context, componentStatics);
1212
return {};
1313
},
1414
componentWillMount: function() {
@@ -17,14 +17,14 @@ function _createReactDartComponentClassConfig(dartInteropStatics, componentStati
1717
componentDidMount: function() {
1818
dartInteropStatics.handleComponentDidMount(this.dartComponent);
1919
},
20-
componentWillReceiveProps: function(nextProps) {
21-
dartInteropStatics.handleComponentWillReceiveProps(this.dartComponent, nextProps.internal);
20+
componentWillReceiveProps: function(nextProps, nextContext) {
21+
dartInteropStatics.handleComponentWillReceiveProps(this.dartComponent, nextProps.internal, nextContext);
2222
},
23-
shouldComponentUpdate: function(nextProps, nextState) {
24-
return dartInteropStatics.handleShouldComponentUpdate(this.dartComponent);
23+
shouldComponentUpdate: function(nextProps, nextState, nextContext) {
24+
return dartInteropStatics.handleShouldComponentUpdate(this.dartComponent, nextContext);
2525
},
26-
componentWillUpdate: function(nextProps, nextState) {
27-
dartInteropStatics.handleComponentWillUpdate(this.dartComponent);
26+
componentWillUpdate: function(nextProps, nextState, nextContext) {
27+
dartInteropStatics.handleComponentWillUpdate(this.dartComponent, nextContext);
2828
},
2929
componentDidUpdate: function(prevProps, prevState) {
3030
dartInteropStatics.handleComponentDidUpdate(this.dartComponent, prevProps.internal);
@@ -36,6 +36,34 @@ function _createReactDartComponentClassConfig(dartInteropStatics, componentStati
3636
return dartInteropStatics.handleRender(this.dartComponent);
3737
}
3838
};
39+
40+
// React limits the accessible context entries
41+
// to the keys specified in childContextTypes/contextTypes.
42+
43+
var childContextKeys = jsConfig && jsConfig.childContextKeys;
44+
var contextKeys = jsConfig && jsConfig.contextKeys;
45+
46+
if (childContextKeys && childContextKeys.length !== 0) {
47+
config.childContextTypes = {};
48+
for (var i = 0; i < childContextKeys.length; i++) {
49+
config.childContextTypes[childContextKeys[i]] = React.PropTypes.object;
50+
}
51+
52+
// Only declare this when `childContextKeys` is non-empty to avoid unnecessarily
53+
// creating interop context objects for components that won't use it.
54+
config.getChildContext = function() {
55+
return dartInteropStatics.handleGetChildContext(this.dartComponent);
56+
};
57+
}
58+
59+
if (contextKeys && contextKeys.length !== 0) {
60+
config.contextTypes = {};
61+
for (var i = 0; i < contextKeys.length; i++) {
62+
config.contextTypes[contextKeys[i]] = React.PropTypes.object;
63+
}
64+
}
65+
66+
return config;
3967
}
4068

4169
function _markChildValidated(child) {

0 commit comments

Comments
 (0)