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

State instanceid context #182

Merged
merged 18 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions app/docs/md/elements/state/context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: Context
---

The context object enables passing state to child elements without needing to resort to passing attributes down through multiple elements.

## Set parent context

The context object is passed as a key on the state object. Add data to the context object and it will be available to child elements.

[Follow along by checking out the context demo from GitHub →](https://github.com/enhance-dev/context-demo)

Given this markup you can use the context object to pass state directly to a deeply nested child element. Consider the page structure in the example below:

<doc-code filename="app/pages/index.html">

```html
<context-parent>
<my-container>
<my-container>
<my-container>
<context-heading></context-heading>
</my-container>
</my-container>
</my-container>
</context-parent>
```

</doc-code>


Add a heading key to the context object in the parent element:

<doc-code filename="app/pages/index.html">

```javascript
export default function ContextParent({ html, state }) {
const { context } = state
context.heading = 'Heading set via context'
return html`
<style>
:host {
display: block;
height: 100dvh;
padding-top: 3rem;
text-align: center;
font-family: sans-serif;
}
</style>
<slot></slot>
`
}
```

</doc-code>

Render the heading passed via context in the deeply nested child element:
<doc-code filenam="app/elements/context/heading.mjs">

```javascript
export default function ContextHeading({ html, state }) {
const { context } = state
const { heading='Default heading' } = context
return html`
<style>
:host > h1 {
font-size: 1.5rem;
}
</style>
<h1>${heading}</h1>
`
}
```

</doc-code>


4 changes: 3 additions & 1 deletion app/docs/md/elements/state/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ export default function MyElement ({ html, state }) {

</doc-code>

The state object contains two top level entries:
The state object contains four top level entries:

- `attrs`, which contains all the key value pairs of attributes passed into your custom element’s instance
- `store`, which contains the global state of your Enhance application
- `instanceID`, which is a unique ID per instance of Custom Element
- `context`, which is an Object that can be used to pass state to child elements to avoid prop drilling.
kristoferjoseph marked this conversation as resolved.
Show resolved Hide resolved

These two different entries allow you to work with both basic and complex state in powerful ways without the need for complex abstractions or third party libraries.
kristoferjoseph marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
23 changes: 23 additions & 0 deletions app/docs/md/elements/state/instance-id.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: Instance ID
---

`instanceID` is a unique identifier that is generated per Custom Element instance. This enables you to differentiate between multiple instances of the same element on a page. It can also be useful when using a string based diffing library like [Morphdom](https://github.com/patrick-steele-idem/morphdom) which keys on unique identifiers to know when to update versus replace an element.
kristoferjoseph marked this conversation as resolved.
Show resolved Hide resolved

```javascript
export default function MyCard({ html, state }) {
const { attrs={}, instanceID='' } = state
const { content='', heading='' } = attrs

return html`
<figure id="figure-${instanceID}">
<h2>${heading}</h2>
<p>${content}</p>
</figure>
`
}
```

<doc-callout mark="ℹ️">
Pro tip: As in the example above, prefix the id with the element name in order to use the id with multiple child elements.
</doc-callout>
10 changes: 9 additions & 1 deletion app/docs/nav-data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,15 @@ export const data = [
path: '/docs/elements/state/',
label: 'State',
hasChildren: true,
items: ['attributes', 'store'],
items: [
'attributes',
'store',
{
slug: 'instance-id',
label: 'Instance ID',
},
'context',
],
},
],
},
Expand Down
1 change: 1 addition & 0 deletions scripts/dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ lowercas(e|ed)
MDN
MDN's
mixi(n|ns)
Morphdom
natively
Netlify
polyfills
Expand Down