Skip to content

Commit

Permalink
Merge pull request #1901 from preactjs/fix/add-scu-for-consumer
Browse files Browse the repository at this point in the history
(fix) Add scu check for context.Consumer
  • Loading branch information
marvinhagemeister committed Aug 28, 2019
2 parents 4a581a1 + 4c22114 commit a16af18
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/create-context.js
Expand Up @@ -13,6 +13,9 @@ export function createContext(defaultValue) {
_id: '__cC' + i++,
_defaultValue: defaultValue,
Consumer(props, context) {
this.shouldComponentUpdate = function (_props, _state, _context) {
return _context !== context;
};
return props.children(context);
},
Provider(props) {
Expand Down
48 changes: 48 additions & 0 deletions test/browser/createContext.test.js
Expand Up @@ -351,6 +351,54 @@ describe('createContext', () => {
expect(scratch.innerHTML).to.equal('<div>b - 1</div><div>a - 1</div>');
});

it('should not re-render the consumer if the context doesn\'t change', () => {
const { Provider, Consumer } = createContext();
const CONTEXT = { i: 1 };

class Inner extends Component {
render(props) {
return <div>{props.i}</div>;
}
}

sinon.spy(Inner.prototype, 'render');

render(
<Provider value={CONTEXT}>
<Consumer>
{data => <Inner {...data} />}
</Consumer>
</Provider>,
scratch
);

render(
<Provider value={CONTEXT}>
<Consumer>
{data => <Inner {...data} />}
</Consumer>
</Provider>,
scratch
);

// Rendered twice, should called just one 'Consumer' render
expect(Inner.prototype.render).to.have.been.calledOnce.and.calledWithMatch(CONTEXT, {}, { ['__cC' + (ctxId - 1)]: {} });
expect(scratch.innerHTML).to.equal('<div>1</div>');

render(
<Provider value={{ i: 2 }}>
<Consumer>
{data => <Inner {...data} />}
</Consumer>
</Provider>,
scratch
);

// Rendered three times, should call 'Consumer' render two times
expect(Inner.prototype.render).to.have.been.calledTwice.and.calledWithMatch({ i: 2 }, {}, { ['__cC' + (ctxId - 1)]: {} });
expect(scratch.innerHTML).to.equal('<div>2</div>');
});

describe('class.contextType', () => {
it('should use default value', () => {
const ctx = createContext('foo');
Expand Down

0 comments on commit a16af18

Please sign in to comment.