-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Added support for React.memo #1914
Conversation
When I used the code directly from #1875 (comment) (that you have ported to enzyme) it works, but only for top level memo'd components. If there are nested components that are wrapped in memo(), they still display in the DOM as [object Object]. Does this code address that? I've had to mock every "sub" memo wrapped component using Jest, otherwise the component isn't searchable by name in the DOM. |
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.
Thanks, great start!
Can we make the shallow and mount tests as close to identical as possible?
Let's also add some debug
tests for this.
@@ -513,6 +527,7 @@ class ReactSixteenAdapter extends EnzymeAdapter { | |||
switch ($$typeofType) { | |||
case ContextConsumer || NaN: return 'ContextConsumer'; | |||
case ContextProvider || NaN: return 'ContextProvider'; | |||
case Symbol.for('react.memo') || NaN: return 'Memo'; |
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.
case Symbol.for('react.memo') || NaN: return 'Memo'; | |
case REACT_MEMO_TYPE || NaN: return 'Memo'; |
@alexgurr Yes. It handles nested memoized components as well. |
@ljharb Thanks so much for the quick response and taking time to review. I have made the changes. |
@@ -249,6 +251,10 @@ function getEmptyStateValue() { | |||
return testRenderer._instance.state; | |||
} | |||
|
|||
function isMemo(node) { | |||
return typeof node.type === 'object' && node.type.$$typeof === REACT_MEMO_TYPE_SYMBOL; |
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.
return typeof node.type === 'object' && node.type.$$typeof === REACT_MEMO_TYPE_SYMBOL; | |
return typeof node.type === 'object' && REACT_MEMO_TYPE && node.type.$$typeof === REACT_MEMO_TYPE; |
const wrapper = mount(<Foo foo="qux" />); | ||
expect(wrapper.debug()).to.equal(`<Component foo="qux"> | ||
<div> | ||
<InnerComp> |
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.
hmm - i'd expect some sort of indication here that it's memoized.
ahhhhh i see that That means we'll have to temporarily hardcode it with |
@ljharb I will then wait for the PR in react to be merged, and will update this PR. |
@Koragan: Sure. will update it soon |
@Koragan the PR is merged, but react-is still hasn't been updated. |
When can we expect this patch to be published? A few of the production project that we're working on depend on it. |
@phenax first we have to wait until react-is v16 gets updated. |
react-is seems to have support for React Memo: https://github.com/facebook/react/blob/master/packages/react-is/src/ReactIs.js#L120 What exactly is pending? 🤔 |
@amite yes, it's been merged, but not yet released to npm by the react team. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
I've updated |
ba622ce
to
bcbb1e8
Compare
The underlying problem has been fixed and this branch rebased. |
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.
Turns out this still needs some work; React itself seems to not render an additional component in the tree for memoized components, so you can't actually .find
by a memoized instance directly (unless we unwrap the memoized constructor and search instead for the inner one, and do the reverse in shallow
).
I'll try to see what I can do.
Any update? |
No update yet. I've rebased this; I'll give it another pass tomorrow. |
Btw, there appear to be two React memo tags, not just one: MemoComponent (currently tag 14) and SimpleMemoComponent (currently tag 15). I just got bitten by this on our in-house custom-patched enzyme where we were only coping with tag 15, and I suddenly hit a 14 tag. I'm not at all sure of the exact details as I only got hit by this a few minutes ago, but it looks like React.memo(fn) gets you a simple component (tag 15) and React.memo(class) gets you a non-simple component (tag 14). I think the PR at present would only cope with tag 15. |
I've done a bit more digging, and it is the case that there's one tag type for Details: https://codesandbox.io/s/kwvx4qwxyo (tags are output to the console) |
b5dee45
to
5649868
Compare
I've rebased and updated this to have tests for both class-based and SFC components. facebook/react#14807 may be a blocker. |
Btw, React are trying to move away from the term 'SFC': |
Per facebook/react#14807 (comment), the shallow renderer will need to be updated before this can go in as is. |
Any update ? If it's not easy / possible to make it works for class component, can not we go incrementally ? Actually it does not work for both functional component and class component. A first implementation working only for functional component is still better. |
@VincentLanglet no, it'd be better to have zero support than partial support, and either way this is blocked on react's shallow renderer change. |
Support for the case that 99% of people actually want to use memo for (functional components) seems to be a pretty good reason to merge partial support to me. Usage with classes, while supported by React, isn't actually documented anywhere, and I would say it's an edge case or at least very niche. The failing test is only related to class components so far as I can tell, so if support for that was moved to a separate PR this would be mergeable, we're not waiting on any dependencies for functional components, right? |
OK, that's a reasonable argument. I suppose it'll just "start working" once react-test-renderer fixes facebook/react#14807 (comment), at which point we can update the tests here. |
- [new] Added support for React.memo (#1914) - [meta] add "directory" field to package.json - [refactor] use `displayNameOfNode` instead of `function.prototype.name` directly
@@ -540,6 +571,7 @@ class ReactSixteenAdapter extends EnzymeAdapter { | |||
switch ($$typeofType) { | |||
case ContextConsumer || NaN: return 'ContextConsumer'; | |||
case ContextProvider || NaN: return 'ContextProvider'; | |||
case Memo || NaN: return displayNameOfNode(type.type); |
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.
displayName is broken 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.
Can you elaborate? a new issue would be ideal.
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.
always getting displayName
"Component" with React.memo()
. need to set correct displayName
each time after applying React.memo()
.
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.
@TymchenkoOleksandr would you mind filing a new issue, and fill out the template? that way I'll be able to fix it more quickly.
This is based on and fixes #1875.