-
Notifications
You must be signed in to change notification settings - Fork 19
Conversation
Codecov Report
@@ Coverage Diff @@
## master #100 +/- ##
==========================================
- Coverage 96.45% 96.32% -0.14%
==========================================
Files 65 66 +1
Lines 480 490 +10
==========================================
+ Hits 463 472 +9
- Misses 17 18 +1
Continue to review full report at Codecov.
|
src/utils/WeakMap.js
Outdated
@@ -0,0 +1,3 @@ | |||
import WeakMap from 'es6-weak-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.
I used es6-weak-map
to polyfill WeakMap
. If it's undesirable to add this dependency, I guess we could manually implement a fallback to using a list here - I didn't try to dive deep into the react-proxy
discussions re polyfills/fallbacks, but es6-weak-map
appears to have O(1) lookup time (rather than O(n) for a list)
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.
Yes but it seems that this polyfill is setting a property on the weakly referenced object (in our case, the enhanced React component) so it would defeat the purpose of this PR.
I'm afraid we'll have to stick to using a list unfortunately.
If we wanted to have O(1)-ish lookup time, we could bucketize this list by taking advantage of the fact that the weakly referenced objects are components and that they (may) have a displayName
or name
property that we could use as bucket names.
This somehow feels a bit "clumsy" to me though. I am starting to wonder if the better way would not simply be to disable the compactable behavior of components in environments where WeakMap
is not supported (that is, IE < 11).
How do you feel about this?
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.
Pinging @neoziro as he may have an opinion on this.
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.
@matthieuprat ah ok I thought that perhaps it was safe (hidden from hoist-non-react-statics
) because the referenced implementation describes it as
In a nutshell, the WeakMap shim emulates a WeakMap by adding a hidden property to the key that associates the weak map with the retained object. The shim overrides the ECMAScript 5 methods to cover its tracks.
But indeed, if I change the import from es6-weak-map
to es6-weak-map/polyfill
(which always uses the polyfill), tests fail
So for now removed es6-weak-map
and implemented your suggestion of disabling compactable behavior (by making our utils/WeakMap
not track anything if WeakMap
does not exist) - not sure how to test the fallback behavior, if I change export default WeakMap || NonTrackingDummyWeakMap
to export default NonTrackingDummyWeakMap
, it is just "should be merged" tests (and debug
test) that fail
I'm not familiar enough with recompact
internals to know if disabling compactable behavior when WeakMap
is missing is reasonable, but seems like it would make sense if that means that it will behave more like recompose
(separate HOCs in the component hierarchy for each recompact
HOC used)?
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 think it is reasonable. It will indeed behave more like recompose.
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.
One way of testing this behavior would be to create another test file and override the WeakMap
global before require
ing HOCs that directly or indirectly depend on src/utils/WeakMap
:
delete global.WeakMap
const { withProps } = require('..')
test('NonTrackingDummyWeakMap fallback', () => { /* ... */ })
const createComponentFromMappers = (mappers, childFactory) => { | ||
const { observablesKey: OBSERVABLES } = getConfig() | ||
const CONTEXT_TYPES = { [OBSERVABLES]: observablePropType } | ||
|
||
return class extends Component { | ||
const Component = class extends React.Component { | ||
static [MAPPERS_INFO] = { mappers, childFactory } |
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 tried following same pattern as in createCompactableHOC
(which is what react-proxy
does) to get rid of MAPPERS_INFO
and store { mappers, childFactory }
as the value in allMapperComponents
, but was running into errors - don't see the harm in still accessing via MAPPERS_INFO
as long as we aren't using its presence to determine whether isMapperComponent()
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 think you're right.
src/utils/createCompactableHOC.js
Outdated
const isCompactable = Component => | ||
typeof Component === 'function' && Component[compactable] | ||
typeof Component === 'function' && allCompactableComponents.has(Component) |
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.
Don't know if it makes sense to get rid of typeof Component === 'function'
(wasn't sure what it was guarding against/optimizing previously)?
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.
IMO, it was defensive programming (so that isCompactable(null)
would return false
instead of throwing a TypeError
for instance).
I think we can probably get rid of it now that we're using a WeakMap
.
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.
@matthieuprat ok removed typeof
check here and in isMapperComponent()
@@ -39,4 +39,31 @@ describe('withProps', () => { | |||
) | |||
expect(wrapper.equals(<div />)).toBeTruthy() | |||
}) | |||
|
|||
it("doesn't compact surrounded HOC that hoists statics", () => { |
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 tests isCompactable()
(test fails against master
version of utils/createCompactableHOC
)
expect(wrapper.prop('foo')).toBe('bar') | ||
}) | ||
|
||
it("doesn't compact double-surrounded HOC that hoists statics", () => { |
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 tests isMapperComponent()
(test fails against master
version of utils/createHOCFromMapper
src/utils/WeakMap.js
Outdated
@@ -0,0 +1,9 @@ | |||
class NonTrackingDummyWeakMap { | |||
get() {} | |||
set() {} |
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.
Might be worth retuning this
so that our NonTrackingDummyWeakMap
behaves like WeakMap
with regard to chaining.
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.
@matthieuprat ok updated
src/utils/WeakMap.js
Outdated
} | ||
} | ||
|
||
export default WeakMap || NonTrackingDummyWeakMap |
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 think this would throw a ReferenceError
if WeakMap
is not defined.
Maybe we could go with something like the following:
export default (typeof WeakMap === 'undefined'
? NonTrackingDummyWeakMap
: WeakMap)
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.
@matthieuprat ok updated
You can add |
Also, you may want to run |
src/utils/WeakMap.js
Outdated
} | ||
} | ||
|
||
export default WeakMap || NonTrackingDummyWeakMap |
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.
@matthieuprat ok updated
src/utils/WeakMap.js
Outdated
@@ -0,0 +1,9 @@ | |||
class NonTrackingDummyWeakMap { | |||
get() {} | |||
set() {} |
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.
@matthieuprat ok updated
@@ -0,0 +1,16 @@ | |||
/* eslint-disable class-methods-use-this */ |
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.
@matthieuprat sorry for build failure, yarn test
was passing, now I'm running yarn lint && yarn test
import React from 'react' | ||
import { shallow } from 'enzyme' | ||
|
||
describe('withProps using NonTrackingDummyWeakMap fallback', () => { |
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.
@matthieuprat added tests for fallback NonTrackingDummyWeakMap
behavior
Thank you! 🎉 |
Fixes #97. Replaces #95
In this PR:
WeakMap
(or polyfilled version) rather than static properties to keep track of whetherisCompactable()
/isMapperComponent()