Skip to content
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

Merged
merged 2 commits into from
Feb 26, 2019
Merged

Added support for React.memo #1914

merged 2 commits into from
Feb 26, 2019

Conversation

jintoppy
Copy link
Contributor

@jintoppy jintoppy commented Nov 22, 2018

This is based on and fixes #1875.

@alexgurr
Copy link

alexgurr commented Nov 22, 2018

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.

Copy link
Member

@ljharb ljharb left a 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';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
case Symbol.for('react.memo') || NaN: return 'Memo';
case REACT_MEMO_TYPE || NaN: return 'Memo';

packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx Outdated Show resolved Hide resolved
packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx Outdated Show resolved Hide resolved
packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx Outdated Show resolved Hide resolved
packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx Outdated Show resolved Hide resolved
@jintoppy
Copy link
Contributor Author

@alexgurr Yes. It handles nested memoized components as well.

@jintoppy
Copy link
Contributor Author

@ljharb Thanks so much for the quick response and taking time to review. I have made the changes.
REACT_MEMO_TYPE was coming as undefined. So, I added a null check also. Not sure if I am doing that in the right way. Please check and let me know

@@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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>
Copy link
Member

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.

@ljharb
Copy link
Member

ljharb commented Nov 26, 2018

ahhhhh i see that REACT_MEMO_TYPE isn't even exported :-/ https://unpkg.com/react-is@16.6.3/cjs/react-is.development.js

That means we'll have to temporarily hardcode it with var hasSymbol = typeof Symbol === 'function' && Symbol.for; var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;, which is a shame.

@jintoppy
Copy link
Contributor Author

@ljharb I will then wait for the PR in react to be merged, and will update this PR.

@TaylorClay
Copy link

@jintoppy
Copy link
Contributor Author

@Koragan: Sure. will update it soon

@ljharb
Copy link
Member

ljharb commented Nov 29, 2018

@Koragan the PR is merged, but react-is still hasn't been updated.

@phenax
Copy link

phenax commented Dec 3, 2018

When can we expect this patch to be published? A few of the production project that we're working on depend on it.

@ljharb
Copy link
Member

ljharb commented Dec 3, 2018

@phenax first we have to wait until react-is v16 gets updated.

@amite
Copy link

amite commented Dec 3, 2018

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? 🤔

@ljharb
Copy link
Member

ljharb commented Dec 3, 2018

@amite yes, it's been merged, but not yet released to npm by the react team.

@rpearce

This comment has been minimized.

@jintoppy

This comment has been minimized.

@rpearce

This comment has been minimized.

@MarceloAlves
Copy link

react-is 16.7.0 was finally released 🎉

@ljharb
Copy link
Member

ljharb commented Dec 21, 2018

I've updated react-is in master and rebased this branch. I'm not sure what's up with the test failures; it might be an issue in enzyme's overall test setup. I'll look into it.

@ljharb ljharb force-pushed the master branch 3 times, most recently from ba622ce to bcbb1e8 Compare December 22, 2018 17:49
@ljharb
Copy link
Member

ljharb commented Dec 22, 2018

The underlying problem has been fixed and this branch rebased.

Copy link
Member

@ljharb ljharb left a 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.

@copiali
Copy link

copiali commented Jan 14, 2019

Any update?

@ljharb
Copy link
Member

ljharb commented Feb 7, 2019

No update yet. I've rebased this; I'll give it another pass tomorrow.

@RoystonS
Copy link

RoystonS commented Feb 7, 2019

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.

@RoystonS
Copy link

RoystonS commented Feb 7, 2019

I've done a bit more digging, and it is the case that there's one tag type for React.memo(FunctionalComponent) and a different tag type for React.memo(ClassComponent)

Details: https://codesandbox.io/s/kwvx4qwxyo (tags are output to the console)

@ljharb
Copy link
Member

ljharb commented Feb 9, 2019

I've rebased and updated this to have tests for both class-based and SFC components.

facebook/react#14807 may be a blocker.

@RoystonS
Copy link

RoystonS commented Feb 9, 2019

Btw, React are trying to move away from the term 'SFC':
https://twitter.com/dan_abramov/status/1057625147216220162

@ljharb
Copy link
Member

ljharb commented Feb 10, 2019

Per facebook/react#14807 (comment), the shallow renderer will need to be updated before this can go in as is.

@VincentLanglet
Copy link

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.

@ljharb
Copy link
Member

ljharb commented Feb 22, 2019

@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.

@mattdarveniza
Copy link

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?

@ljharb
Copy link
Member

ljharb commented Feb 26, 2019

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.

@ljharb ljharb merged commit 6b3274b into enzymejs:master Feb 26, 2019
ljharb added a commit that referenced this pull request Feb 26, 2019
 - [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);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

displayName is broken here!

Copy link
Member

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.

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().

Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New memo feature from React 16.6 is not supported