@wcom/contextdeprecated

Pass props down web component trees easily.

Usage no npm install needed!

<script type="module">
  import wcomContext from 'https://cdn.skypack.dev/@wcom/context';
</script>

README

@wcom/context

package-badge license-badge coverage-badge semantic-release-badge

Introduction

The inner workings and implementation are thanks to @furf.

This library enables data to be passed down component trees without having to pass props down manually. This library is expected to be used with TypeScript, make sure to set experimentalDecorators to true in tsconfig.json.

This library currently does not work with Stencil anymore, any PR is welcomed to add support!

Install

# npm
$: npm install @wcom/context

# yarn
$: yarn add @wcom/context

# pnpm
$: pnpm install @wcom/context

Usage

If you've used React.ContextProvider before you should already have the concepts down. Simply when we create a context we receive a provide and consume decorator. Each context can only have a single provider who is responsible for updating the current value. However, each context can have many consumers who simply listen for updates on when the value is changed. A context can be any data type such as a string, boolean, array, object etc.

Important: You might be familiar with this pattern by now but do no update arrays or objects in-place with methods like array.push() or object[key] = value, simply because this will mean the equality check will never be false so no provider update will be emitted. You can update an array like so array = [...array, 'newValue'] and object like so object = { ...object, [key]: value }.

Here's a simple diagram:

  • Provider (Let's pretend here we are providing some context)
    • Child A
      • Child B (Here we can consume that context without passing a prop from Provider -> A -> B).

One last thing to keep in mind is that a consumer will connect to it's nearest provider, for example:

  • Provider (Let's pretend here we are providing some context)
    • Child A
      • Provider (Here we are providing the same context)
        • Child B (This will consume the parent provider instead of the Provider higher in the tree).

createContext<T>(defaultValue T): Context<T>

This is the bread and butter of this library. It simply creates a new Context which looks like this:

interface Context<T> {
  provide(): PropertyDecorator
  consume(): PropertyDecorator
  defaultValue?: T
}
  1. Let's create our context...
import createContext from '@wcom/context';

export const myContext = createContext(10);
  1. Setup a provider...
import { myContext } from './context';

class MyProvider extends HTMLElement {
  @myContext.provide()
  someContext = myContext.defaultValue;

  // Setup slot etc. ...

  // Update context by simply setting new values.
  onUpdateContext() {
    this.someContext = 20;
  }
}
  1. Setup a consumer...
import { myContext } from './context';

class MyConsumer extends HTMLElement {
  // This will now be kept in-sync with the value in `MyProvider`.
  @myContext.consume()
  someContext = myContext.defaultValue;

   // ...
}
  1. Implementation in DOM...
<my-provider>
  <my-consumer></my-consumer>
</my-provider>

And you're done 🎉  That's all there is to it.

Lit Example

The usage is exactly the same as above except you might want to trigger a re-render on changes, so set a @internalProperty decorator accordingly like so...

import { myContext } from './context';
import { internalProperty, LitElement } from 'lit-element';

class MyComponent extends LitElement {
  @internalProperty()
  @myContext.consume()
  someContext = myContext.defaultValue;
  
  // ...
}