Skip to content

Commit

Permalink
[Fix] ref: ensure that the prop value is not a component
Browse files Browse the repository at this point in the history
  • Loading branch information
ahuth authored and ljharb committed Apr 4, 2019
1 parent 22babe9 commit 3070a63
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 5 deletions.
10 changes: 9 additions & 1 deletion src/ref.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Component, PureComponent } from 'react';
import isPlainObject from './helpers/isPlainObject';
import wrapValidator from './helpers/wrapValidator';

Expand All @@ -9,10 +10,17 @@ function isNewRef(prop) {
return ownProperties.length === 1 && ownProperties[0] === 'current';
}

function isCallbackRef(prop) {
return typeof prop === 'function'
&& !Object.prototype.isPrototypeOf.call(Component, prop)
&& (!PureComponent || !Object.prototype.isPrototypeOf.call(PureComponent, prop))
&& prop.length === 1;
}

function requiredRef(props, propName, componentName) {
const propValue = props[propName];

if (typeof propValue === 'function' || isNewRef(propValue)) {
if (isCallbackRef(propValue) || isNewRef(propValue)) {
return null;
}

Expand Down
44 changes: 40 additions & 4 deletions test/ref.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,32 @@ describe('ref', () => {
});

it('passes with legacy refs', () => {
assertPasses(validator, <div someRef={() => {}} />, 'someRef');
assertPasses(validator, <div someRef={(node) => {}} />, 'someRef'); // eslint-disable-line no-unused-vars
});

it('passes with ref objects', () => {
assertPasses(validator, <div someRef={React.createRef()} />, 'someRef');
});

it('fails with non-refs', () => {
it('fails with React components', () => {
class A extends React.Component {
constructor(props) {} // eslint-disable-line
}
assertFails(validator, <div someRef={A} />, 'someRef');
});

it('fails with React pure components', () => {
class B extends React.PureComponent {
constructor(props) {} // eslint-disable-line
}
assertFails(validator, <div someRef={B} />, 'someRef');
});

it('fails with non-ref functions', () => {
assertFails(validator, <div someRef={() => {}} />, 'someRef');
});

it('fails with other non-refs', () => {
assertFails(validator, <div someRef={666} />, 'someRef');
});
});
Expand All @@ -56,14 +74,32 @@ describe('ref', () => {
});

it('passes with legacy refs', () => {
assertPasses(validator, <div someRef={() => {}} />, 'someRef');
assertPasses(validator, <div someRef={(node) => {}} />, 'someRef'); // eslint-disable-line no-unused-vars
});

it('passes with ref objects', () => {
assertPasses(validator, <div someRef={React.createRef()} />, 'someRef');
});

it('fails with non-refs', () => {
it('fails with React components', () => {
class A extends React.Component {
constructor(props) {} // eslint-disable-line
}
assertFails(validator, <div someRef={A} />, 'someRef');
});

it('fails with React pure components', () => {
class B extends React.PureComponent {
constructor(props) {} // eslint-disable-line
}
assertFails(validator, <div someRef={B} />, 'someRef');
});

it('fails with non-ref functions', () => {
assertFails(validator, <div someRef={() => {}} />, 'someRef');
});

it('fails with other non-refs', () => {
assertFails(validator, <div someRef={666} />, 'someRef');
});
});
Expand Down

0 comments on commit 3070a63

Please sign in to comment.