Skip to content

Commit

Permalink
Start refactor to provider check for emit instead of SCU Consum… (#1931)
Browse files Browse the repository at this point in the history
Start refactor to provider check for emit instead of SCU Consumer
  • Loading branch information
marvinhagemeister authored Sep 22, 2019
2 parents 8c6ac43 + 6d88906 commit 9eba4e0
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 46 deletions.
24 changes: 11 additions & 13 deletions src/create-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@ export function createContext(defaultValue) {
_id: '__cC' + i++,
_defaultValue: defaultValue,
Consumer(props, context) {

this.shouldComponentUpdate = function (_props, _state, _context) {
return _context !== context || props.children !== _props.children;
};

return props.children(context);
},
Provider(props) {
Expand All @@ -27,14 +22,17 @@ export function createContext(defaultValue) {
ctx[context._id] = this;
return ctx;
};
this.shouldComponentUpdate = props => {
subs.some(c => {
// Check if still mounted
if (c._parentDom) {
c.context = props.value;
enqueueRender(c);
}
});
this.shouldComponentUpdate = _props => {
if (props.value !== _props.value) {
ctx[context._id].props.value = _props.value;
subs.some(c => {
// Check if still mounted
if (c._parentDom) {
c.context = _props.value;
enqueueRender(c);
}
});
}
};
this.sub = (c) => {
subs.push(c);
Expand Down
126 changes: 93 additions & 33 deletions test/browser/createContext.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { setupRerender } from 'preact/test-utils';
import { setupRerender, act } from 'preact/test-utils';
import { createElement as h, render, Component, createContext } from '../../src/index';
import { setupScratch, teardown } from '../_util/helpers';
import { Fragment } from '../../src';
Expand Down Expand Up @@ -355,6 +355,16 @@ describe('createContext', () => {
const { Provider, Consumer } = createContext();
const CONTEXT = { i: 1 };

class NoUpdate extends Component {
shouldComponentUpdate() {
return false;
}

render() {
return this.props.children;
}
}

class Inner extends Component {
render(props) {
return <div>{props.i}</div>;
Expand All @@ -363,22 +373,22 @@ describe('createContext', () => {

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

const Child = data => <Inner {...data} />;

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

render(
<Provider value={CONTEXT}>
<Consumer>
{Child}
</Consumer>
<NoUpdate>
<Consumer>{data => <Inner {...data} />}</Consumer>
</NoUpdate>
</Provider>,
scratch
);
Expand All @@ -387,20 +397,66 @@ describe('createContext', () => {
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>
{Child}
</Consumer>
</Provider>,
scratch
);
act(() => {
render(
<Provider value={{ i: 2 }}>
<NoUpdate>
<Consumer>{data => <Inner {...data} />}</Consumer>
</NoUpdate>
</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>');
});

it('should allow for updates of props', () => {
let app;
const { Provider, Consumer } = createContext();
class App extends Component {
constructor(props) {
super(props);
this.state = {
status: 'initial'
};

this.renderInner = this.renderInner.bind(this);

app = this;
}

renderInner(value) {
return <p>{value}: {this.state.status}</p>;
}

render() {
return (
<Provider value="value">
<Consumer>
{this.renderInner}
</Consumer>
</Provider>
);
}
}

act(() => {
render(<App />, scratch);
});

expect(scratch.innerHTML).to.equal('<p>value: initial</p>');

act(() => {
app.setState({ status: 'updated' });
rerender();
});

expect(scratch.innerHTML).to.equal('<p>value: updated</p>');
});

it('should re-render the consumer if the children change', () => {
const { Provider, Consumer } = createContext();
const CONTEXT = { i: 1 };
Expand All @@ -413,23 +469,27 @@ describe('createContext', () => {

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

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

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

// Not calling re-render since it's gonna get called with the same Consumer function
render(
<Provider value={CONTEXT}>
<Consumer>
{data => <Inner {...data} />}
</Consumer>
</Provider>,
scratch
);
});

// Rendered twice, with two different children for consumer, should render twice
expect(Inner.prototype.render).to.have.been.calledTwice;
Expand Down

0 comments on commit 9eba4e0

Please sign in to comment.