UNPKG

2.16 kBJavaScriptView Raw
1import { enqueueRender } from './component';
2
3export let i = 0;
4
5export function createContext(defaultValue, contextId) {
6 contextId = '__cC' + i++;
7
8 const context = {
9 _id: contextId,
10 _defaultValue: defaultValue,
11 /** @type {import('./internal').FunctionComponent} */
12 Consumer(props, contextValue) {
13 // return props.children(
14 // context[contextId] ? context[contextId].props.value : defaultValue
15 // );
16 return props.children(contextValue);
17 },
18 /** @type {import('./internal').FunctionComponent} */
19 Provider(props) {
20 if (!this.getChildContext) {
21 let subs = [];
22 let ctx = {};
23 ctx[contextId] = this;
24
25 this.getChildContext = () => ctx;
26
27 this.shouldComponentUpdate = function(_props) {
28 if (this.props.value !== _props.value) {
29 // I think the forced value propagation here was only needed when `options.debounceRendering` was being bypassed:
30 // https://github.com/preactjs/preact/commit/4d339fb803bea09e9f198abf38ca1bf8ea4b7771#diff-54682ce380935a717e41b8bfc54737f6R358
31 // In those cases though, even with the value corrected, we're double-rendering all nodes.
32 // It might be better to just tell folks not to use force-sync mode.
33 // Currently, using `useContext()` in a class component will overwrite its `this.context` value.
34 // subs.some(c => {
35 // c.context = _props.value;
36 // enqueueRender(c);
37 // });
38
39 // subs.some(c => {
40 // c.context[contextId] = _props.value;
41 // enqueueRender(c);
42 // });
43 subs.some(enqueueRender);
44 }
45 };
46
47 this.sub = c => {
48 subs.push(c);
49 let old = c.componentWillUnmount;
50 c.componentWillUnmount = () => {
51 subs.splice(subs.indexOf(c), 1);
52 if (old) old.call(c);
53 };
54 };
55 }
56
57 return props.children;
58 }
59 };
60
61 // Devtools needs access to the context object when it
62 // encounters a Provider. This is necessary to support
63 // setting `displayName` on the context object instead
64 // of on the component itself. See:
65 // https://reactjs.org/docs/context.html#contextdisplayname
66
67 return (context.Provider._contextRef = context.Consumer.contextType = context);
68}