Skip to content

Commit 3071b6c

Browse files
authored
fix: only provide first context if multiple SM factories of same type (#52)
1 parent 361ece8 commit 3071b6c

File tree

12 files changed

+263
-18
lines changed

12 files changed

+263
-18
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { defineState } from '@lwc/state';
2+
3+
export default defineState((atom) => (initialName = 'anotherFoo') => ({
4+
name: atom(initialName),
5+
}));

example/src/modules/x/childState/childState.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { defineState } from '@lwc/state';
22
import parentStateFactory from 'x/parentState';
3+
import anotherParentStateFactory from 'x/anotherParentState';
34

45
export default defineState((atom, _computed, update, fromContext) => (initialName = 'bar') => {
56
const name = atom(initialName);
67
const parentState = fromContext(parentStateFactory);
8+
const anotherParentState = fromContext(anotherParentStateFactory);
79

810
const updateName = update({ name }, (_, newName) => ({
911
name: newName,
@@ -13,5 +15,6 @@ export default defineState((atom, _computed, update, fromContext) => (initialNam
1315
name,
1416
updateName,
1517
parentState,
18+
anotherParentState,
1619
};
1720
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template>
22
<h3>Child</h3>
33
<p class='child-content'>nameProvidedByParent: {nameProvidedByParent}</p>
4+
<p class='another-child-content'>AnotherNameProvidedByParent: {anotherNameProvidedByParent}</p>
45
<x-context-grand-child></x-context-grand-child>
56
</template>

example/src/modules/x/contextChild/contextChild.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ export default class ContextChild extends ContextfulLightningElement {
77
get nameProvidedByParent() {
88
return this.childState.value.parentState.value?.name ?? 'not available';
99
}
10+
11+
get anotherNameProvidedByParent() {
12+
return this.childState.value.anotherParentState.value?.name ?? 'not available';
13+
}
1014
}

example/src/modules/x/contextParent/contextParent.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import { api } from 'lwc';
22
import { ContextfulLightningElement } from '@lwc/state/context';
33
import parentStateFactory from 'x/parentState';
4+
import anotherParentStateFactory from 'x/anotherParentState';
45

56
export default class ContextParent extends ContextfulLightningElement {
67
@api
78
parentState = parentStateFactory('parentFoo');
89

10+
@api
11+
dupParentState;
12+
13+
anotherParentState = anotherParentStateFactory();
14+
915
@api
1016
hideChild = false;
1117

example/src/modules/x/contextRoot/context.spec.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { expect, querySelectorDeep, clientSideRender } from '@lwc/test-runner';
1+
import { expect, querySelectorDeep, clientSideRender, sinon } from '@lwc/test-runner';
2+
import parentStateFactory from '../parentState/parentState.js';
23

34
const componentPath = import.meta.resolve('./contextRoot.js');
45

@@ -97,6 +98,28 @@ describe('context', () => {
9798
expect(contextParent.parentState.subscribers.size).toBe(1);
9899
});
99100

101+
it('can provide multiple context of different varieties', async () => {
102+
await clientSideRender(parentEl, componentPath, {});
103+
const childContent = querySelectorDeep('.child-content');
104+
const anotherChildContent = querySelectorDeep('.another-child-content');
105+
106+
expect(childContent.innerText).to.include('parentFoo');
107+
expect(anotherChildContent.innerText).to.include('anotherFoo');
108+
});
109+
110+
it('logs an error when multiple contexts of same variety are provided', async () => {
111+
const errorSpy = sinon.spy(console, 'error');
112+
// context parent already has a state manager of type parentStateFactory
113+
await clientSideRender(parentEl, componentPath, {
114+
dupParentState: parentStateFactory(),
115+
});
116+
117+
expect(errorSpy.callCount).to.equal(1);
118+
expect(errorSpy).to.have.been.calledWith(
119+
'Multiple contexts of the same variety were provided. Only the first context will be used.',
120+
);
121+
});
122+
100123
it('children can access context directly with detached fromContext', async () => {
101124
const el = await clientSideRender(parentEl, componentPath, {});
102125
const childWithDetachedFromContext = querySelectorDeep('.child-content-detached', el);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<x-context-parent></x-context-parent>
2+
<x-context-parent dup-parent-state={dupParentState}></x-context-parent>
33
<x-context-lonely-child></x-context-lonely-child>
44
<x-context-parent-detached></x-context-parent-detached>
55
</template>
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
import { LightningElement } from 'lwc';
1+
import { LightningElement, api } from 'lwc';
22

3-
export default class ContextRoot extends LightningElement {}
3+
export default class ContextRoot extends LightningElement {
4+
@api
5+
dupParentState;
6+
}

0 commit comments

Comments
 (0)