Comments (2)
// src/utils/context.ts
import { registerDestructor } from './glimmer/destroyable';
import { Component, RENDER_TREE } from './shared';
const CONTEXTS = new WeakMap<Component<any>, Map<symbol, any>>();
export function getContext<T>(ctx: Component<any>, key: symbol): T | undefined {
let current = ctx;
while (current) {
const context = CONTEXTS.get(current);
if (context?.has(key)) {
return context.get(key);
}
const parent = findParentComponent(current);
current = parent;
}
return undefined;
}
export function setContext<T>(ctx: Component<any>, key: symbol, value: T): void {
if (!CONTEXTS.has(ctx)) {
CONTEXTS.set(ctx, new Map());
}
CONTEXTS.get(ctx)!.set(key, value);
registerDestructor(ctx, () => {
CONTEXTS.get(ctx)!.delete(key);
});
}
function findParentComponent(component: Component<any>): Component<any> | null {
for (const [parent, children] of RENDER_TREE) {
if (children.has(component)) {
return parent;
}
}
return null;
}
Explanation:
findParentComponent
: This new function utilizes theRENDER_TREE
to efficiently find the parent component of a given component.getContext
:- It now iterates up the component tree using
findParentComponent
. - For each ancestor component, it checks if a context value exists for the given key.
- If found, it returns the value.
- If not found in any ancestor, it returns
undefined
.
- It now iterates up the component tree using
Benefits:
- Leverages Existing Structure: This approach leverages the existing
RENDER_TREE
for context lookup, avoiding the need for a separate context tree. - Efficient Lookup: Traversing the
RENDER_TREE
provides a direct path to ancestor components, making context lookup efficient. - No Additional Overhead: This implementation doesn't introduce any significant overhead as it reuses the existing rendering tree structure.
This updated implementation provides a more integrated and efficient way to manage context in GXT by utilizing the internal component tree structure.
from glimmer-next.
Context API: Sharing Data Across Components
GXT's Context API provides a mechanism for sharing data across components without explicitly passing props through every level of the component tree. This is particularly useful for sharing data that is globally relevant, such as:
Use Cases:
- Theming: Share theme information, like colors, fonts, and styles, across the entire application.
- Localization: Provide localized strings and formatting rules to components.
- User Authentication: Make user authentication status and data accessible to components that need it.
- Feature Flags: Control the visibility or behavior of features based on feature flags stored in context.
- Application State: Share application-wide state, such as loading indicators or error messages.
Integration Tests
// src/tests/integration/context-test.gts
import { module, test } from 'qunit';
import { render } from '@lifeart/gxt/test-utils';
import { Component, getContext, provideContext } from '@lifeart/gxt';
const ThemeContext = Symbol('ThemeContext');
class ThemeProvider extends Component {
<template>
{{yield}}
</template>
constructor(args: any) {
super(args);
provideContext(this, ThemeContext, this.args.theme);
}
}
class ThemedButton extends Component {
<template>
<button class={{this.theme.buttonClass}}>
{{yield}}
</button>
</template>
get theme() {
return getContext(this, ThemeContext) || {};
}
}
module('Integration | Context API', function () {
test('provides and consumes context', async function (assert) {
await render(
<template>
<ThemeProvider @theme={{hash buttonClass="bg-blue-500"}}>
<ThemedButton data-test-button>Click me</ThemedButton>
</ThemeProvider>
</template>
);
assert.dom('[data-test-button]').hasClass('bg-blue-500', 'Button receives theme from context');
});
test('context is not available outside the provider', async function (assert) {
await render(
<template>
<ThemeProvider @theme={{hash buttonClass="bg-blue-500"}} />
<ThemedButton data-test-button>Click me</ThemedButton>
</template>
);
assert.dom('[data-test-button]').doesNotHaveClass('bg-blue-500', 'Button does not receive theme outside the provider');
});
test('context lookup traverses the component tree', async function (assert) {
class Layout extends Component {
<template>
{{yield}}
</template>
}
await render(
<template>
<ThemeProvider @theme={{hash buttonClass="bg-blue-500"}}>
<Layout>
<ThemedButton data-test-button>Click me</ThemedButton>
</Layout>
</ThemeProvider>
</template>
);
assert.dom('[data-test-button]').hasClass('bg-blue-500', 'Button receives theme from context through nested components');
});
});
Explanation of Tests:
-
provides and consumes context
:- Renders a
ThemeProvider
that provides a theme context. - Renders a
ThemedButton
inside the provider. - Asserts that the button receives the theme from the context.
- Renders a
-
context is not available outside the provider
:- Renders a
ThemeProvider
and aThemedButton
outside the provider. - Asserts that the button does not receive the theme context.
- Renders a
-
context lookup traverses the component tree
:- Renders a
ThemeProvider
, aLayout
component, and aThemedButton
nested within. - Asserts that the button still receives the theme context even though it's not a direct child of the provider.
- Renders a
These tests demonstrate the basic functionality of the Context API, including providing, consuming, and looking up context values within the component tree.
from glimmer-next.
Related Issues (20)
- gxt - untrack function
- renderComponent should accept instance of Component
- slot default is not set
- gxt main page menu - add slide animation HOT 1
- todo - add test for sync render branch
- if control not working if checked for function HOT 1
- <pre>ReferenceError: document is not defined<br> - glimmer router
- document destroy flow
- improve readonly property support
- Autocode [prompt] [experiment] HOT 2
- [compiler] reuse tags HOT 1
- element helper - style attribute binding issue HOT 1
- glint HOT 1
- Wait for element animations HOT 1
- Introduce mutation transactions? HOT 2
- Add Request component from warp-drive
- Add @effect @willDestroy decorators
- Improve attributes / props flow
- Add test for recursive component rendering
- Special symbols rendering
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from glimmer-next.