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

Start refactor to provider check for emit instead of SCU Consum… #1931

Merged
merged 8 commits into from
Sep 22, 2019
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