-
Notifications
You must be signed in to change notification settings - Fork 67
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
CPLAT-4303: React 16 New Context #160
CPLAT-4303: React 16 New Context #160
Conversation
# Conflicts: # test/js_interop_helpers_test/shared_tests.dart
* master: Bump version meta for 4.6.1 release Use isInstanceOf instead of TypeMatcher widen build package ranges type style map
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kealjones-wk didn't make it all the way through, have a parent teacher conference for Noah this morning at 8:30. Will continue taking a look when I return.
if (nextValue['renderCount'] % 2 == 0) { | ||
result |= 1 << 2; | ||
} | ||
return result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have literally no idea what is happening, or why it is happening. The second argument of createContext
deserves some documentation explaining what it does. For instance, why does it always return an integer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The React team doesn't even have documentation around it. They act as if it doesn't exist even though it obviously does, i think this may still be a WIP/secret or experimental feature...
The idea is that you return a bit that indicates which parts/or how the context value changed, then you can use the observedBits props on a consumer and they will only re-render if the bits they are observing are returned from calculateChangedBits
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the crazy delayed reply here @kealjones-wk - a doc comment about how you perceive it to work (like what you just typed above) would be a great addition!
|
||
class _NewContextConsumerComponent extends react.Component2 { | ||
render() { | ||
return TestNewContext.Consumer({'unstable_observedBits': props['unstable_observedBits']}, (value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we using unstable
ReactJS APIs in something extending from Component2
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just an example but, the unstable_observedBits
prop functions better than the stable version of the prop: observedBits
... thats why its used here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delayed reply.
I get that its just an example... but it is an example intended to exercise the functionality in-lieu of a formal functional test - which is why I'm concerned about our implementation possibly not functioning well with the stable version of observedBits
.
@@ -23,181 +24,17 @@ main() { | |||
JsBackedMap jsBackedMap; | |||
JsBackedMap dynamicJsBackedMap; | |||
|
|||
setUp(() { | |||
testTypeValue(testValue) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type information of testValue is no longer being propagated. Are we sure that this test is equivalent to the old one? @greglittlefield-wf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about this and we may be able to use generics to propagate the static type information, and use JS inlining annotations from package:meta to force dart2js to use that type info (if it doesn't already):
testTypeValue(testValue) { | |
@tryInline | |
void testTypeValue<T>(T testValue) { |
I'll give that a shot locally.
Related: we should update the builder config for this repo to use the Dart 2 equivalent of the trust-type-annotations flag, since that's what we'll be using in prod most of the time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks manually inlining doesn't do much for the dart2js output, but we should add the generics so that both tests aren't essentially just as dynamic
.
I'll make a PR to add those and also add the build.yaml and test changes
test/shared_type_tester.dart
Outdated
import 'package:js/js.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
sharedTypeTests(Function testTypeValue, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This typing should be more specific:
sharedTypeTests(Function testTypeValue, | |
typedef void TestTypeValue<T>(T value); | |
void sharedTypeTests(TestTypeValue testTypeValue, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should avoid unnecessary typedef
s since we're Dart 2 only now... we can just use the new inline Function
syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point; the only reason I put in the typedef was because I wasn't sure if the semantics were the same for generics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in kealjones-wk#3
expect(consumerRef.latestValue, same(typeToTest)); | ||
} | ||
|
||
group('New Context API (Component2 only)', () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any tests that the correct nextContext
arg is passed into shouldComponentUpdate
? I can't seem to find any. If not, could you add some?
bb67481
to
d38c570
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
Really nice work on this @kealjones-wk !!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some things we should address in a follow-up PR, but are good for now:
- Comments in this review
- Comment about testing the
nextContext
value passed into shouldComponentUpdate (the only test we have usesnull
; we should also have a test with another value)
The JS components demo fails in release mode:js_components.dart.js:9006 Uncaught ReferenceError: ui is not defined at js_components.dart.js:9006 at Object.holder.(anonymous function) (http://localhost:8080/js_components/js_components.dart.js:105:35) at _IndexComponent.render$0 (js_components.dart.js:8492) at _handleRender_closure.call$0 (js_components.dart.js:8249) at _RootZone.run$1$1 (js_components.dart.js:5644) at _RootZone.run$1 (js_components.dart.js:5648) at closure_handleRender.call$4 (js_components.dart.js:8240) at Object.Primitives_applyFunction (js_components.dart.js:457) at Object.Function_apply (js_components.dart.js:2451) at _callDartFunctionFast (js_components.dart.js:2791)
This is awesome!!!
+10
|
||
/// Prefix to namespace react-dart symbols | ||
var _reactDartSymbolPrefix = 'react-dart.'; | ||
/// A global symbol to identify javascript objects owned by react-dart context, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#nit
/// A global symbol to identify javascript objects owned by react-dart context, | |
/// A symbol to identify JavaScript objects owned by react-dart context, |
} | ||
|
||
bool handleShouldComponentUpdate(Component2 component, JsMap jsNextProps, JsMap jsNextState) => zone.run(() { | ||
bool handleShouldComponentUpdate(Component2 component, JsMap jsNextProps, JsMap jsNextState, | ||
[dynamic jsNextContext]) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be optional, right?
@@ -587,25 +612,117 @@ ReactDartComponentFactoryProxy _registerComponent(ComponentFactory componentFact | |||
return new ReactDartComponentFactoryProxy(reactComponentClass); | |||
} | |||
|
|||
class _ReactJsContextComponentFactoryProxy extends ReactJsComponentFactoryProxy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could use a doc comment
@greglittlefield-wf if the only test you're referring to is this one: https://github.com/cleandart/react-dart/pull/160/files#diff-c00a02aa016b25a86fb30a2093f935a1R520 because that component it is a child of a context.consumer callback and not a consumer/contextType component itself it will actually never have a The only time i have seen |
Yeah, I think we just need to verify that when it is passed in, that it's valid. |
We may delay this PR until we start work on
ComponentV2
and then implement it inComponentV2
and put Legacy Context back inComponent
but this pr is ready for an implementation CR with this in mind.Merge conflicts are to be expected in the
lib
folders .js and .map files these are generated from thejs_src
files and runningnpm run build
. They will be resolved with a merge of thejs_src
folders and a new build on the wip branch.Description:
React 16 implements a better New Context API.
Changes:
createContext
to react_client.dartcontextType
toreact.Component2
ReactDartContext
that utilize interopReactContext
for use in ReactJSReactJsComponentFactoryProxy
that was originally created by @greglittlefield-wf about 2 years ago, then added aReactJsContextComponentFactoryProxy
for use with react16 and context components.ReactJsComponentFactoryProxy
shouldComponentUpdateWithContext
calculateChangedBits
argument of context.getSnapshotBeforeUpdate
tests to use new shared type testsTesting suggestions:
webdev serve example
and open http://localhost:8080Potential areas of regression: