Skip to content

Commit f2bbdda

Browse files
author
Leo Y. Li
committed
#0: release v1.1.0
1 parent 8ec3f39 commit f2bbdda

File tree

4 files changed

+59
-17
lines changed

4 files changed

+59
-17
lines changed

CHANGELOG.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
---
77

8-
## [1.0.2] - 2019-04-26
8+
## [1.1.0] - 2019-04-28
9+
10+
## Feature
11+
12+
- Expose `._context` object for manual `inject` binding without the `Consumer` component.
13+
14+
## Documentation
15+
16+
- Update API documentation and add library highlights.
17+
18+
19+
## [1.0.2] - 2019-04-27
920

1021
## Documentation
1122

README.md

+36-8
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@
44

55
An abstracted util factory for creating **scoped**, **declarative**, and **reactive** context-components in Vue. This API abstraction is greatly inspired by [`React.createContext`](https://reactjs.org/docs/context.html) using Vue's [`prvide/inject` API](https://vuejs.org/v2/api/#provide-inject) under the hood. The usage and its behaviour is exactly the same as you may expect if you already familiar with React. With this library to power up your Vue application, you then now able to use `prvide/inject` in an explicit, but declarative manner for managing application contexts using component composition. It's just that easy.
66

7+
## ✨ Highlights
8+
9+
- Solve **prop-drilling** without the full state management solution; good for library development.
10+
- Declarative, reusable, but explicit, you know where your data came from and how to access it.
11+
- Easier to debug, just search `Context.Provider` in the devTool then you know where data get injected.
12+
- Free from name clash, there are just no chance to mess up `provide/inject`. Zero overhead!
13+
- Seamless developing experiences for people came from React.
14+
715
## 🧰 Requirements
816

9-
This library recommend to have Vue 2.6+, where Vue introduces the `v-slot` derivative, opening a clean declarative pattern for passing component props in a compositional manner.
17+
This library recommend to have Vue 2.6+, so we can leverage the `v-slot` derivative to write readable code.
1018

1119
## 🎬 Getting started
1220

@@ -18,11 +26,14 @@ yarn add vue-create-context
1826

1927
## 📔 API
2028

29+
It is recommended to read [React context doc](https://reactjs.org/docs/context.html) to have a better idea on the API design. The doc here will just focus on the usage and the difference in Vue.
30+
2131
### `createContext`
2232

2333
```js
24-
import { createContext } from 'vue-create-context';
25-
const MyContext = createContext(defaultValue);
34+
import { createContext } from 'vue-create-context'
35+
36+
const MyContext = createContext(defaultValue)
2637
```
2738

2839
Calling `createContext` with the `defaultValue` to create a context object. The `defaultValue` can be either a referential object or primitive, which is **ONLY** used when the `Consumer` component can not find its conjugated `Provider` above the rendering tree.
@@ -41,18 +52,34 @@ Note: If the provided value is reactive, update this value "reactively" will als
4152

4253
```vue
4354
<MyContext.Consumer v-slot="/* slot props: the value injected by the closed Provider */">
44-
/* you can access the value within the block */
45-
/* note: as a normal renderless component, this block have no access to computed properties */
55+
<!-- you can access the value within the block -->
4656
</MyContext.Consumer>
4757
```
4858

49-
The `Consumer` gives the access to the injected value from the closest `Provider`. Unlike React, where uses the CAAF (children as a function, also known as the "render prop") pattern to access the value, we uses `v-slot` inside the component block template to access the value (the so called "slot props"). If you uses single file component (SFC) or browsers supports ES6+ object spread operator, you can take the advantage of object destructuring (see more on [Vue's official documentation](https://vuejs.org/v2/guide/components-slots.html#Destructuring-Slot-Props)).
59+
The `Consumer` is a _functional_ component gives the access to the injected value from the closest `Provider`. Unlike React, where uses the CAAF (children as a function, also known as the "render prop") pattern to access the value, we uses `v-slot` inside the component block template to access the value (the so called "slot props"). If you uses single file component (SFC) or browsers supports ES6+ object spread operator, you can take the advantage of object destructuring (see more on [Vue's official documentation](https://vuejs.org/v2/guide/components-slots.html#Destructuring-Slot-Props)).
5060

51-
It is worth to mention that due to the current implementation of Vue's scoped slot API, the slot props have to be an object, so it is recommended to give the value as an plan old javascript object (POJO). In the case of the provided value to be a primitive, it will be normalized as an object with a `value` key to get the passed value in `v-slot`, i.e. `{ value: /* your provided value */ }`.
61+
It is worth to mention that due to the current implementation of Vue's scoped slot API, the slot props have to be an object, so it is recommended to give the value as an plan old javascript object (POJO). In the case of the provided value to be a primitive, it will be normalized as an object with a `value` property to get the passed value in `v-slot`, i.e. `{ value: /* your provided value */ }`.
5262

5363
Note: You might be tempted to mutate the injected value from the consumer block. This is generally a bad idea since it violate the principle of "[props down, event up](https://vuejs.org/v2/style-guide/#Implicit-parent-child-communication-use-with-caution)"; therefore, it is recommend to treat the slot props as read only properties. Under the hood, this reactivity behaviour of slot props is just a reflection of the `provide/inject` API.
5464

55-
⚠️ **Caveat**: After chat with Vue's core team member @linusborg in Discord, the current constrain limits the template inside `Consumer` block have no access to the computed properties, but it can access to state value defined in `data` though. Please use it with caution!
65+
### `Context._context`
66+
67+
Internally, calling `createContext` will generate an unique identifier as a key to access the inject value at runtime, that is why there are no such chance to have clashes. But if you need the injected value to be used in `computed` property, then you manually have to setup `inject` property on the component instance (thanks to Vue's core team member @linusborg for pointing out this). For such usage, you can bind the injected context as the following:
68+
69+
```js
70+
{
71+
inject: {
72+
[name]: MyContext._context,
73+
},
74+
computed: {
75+
[something]() {
76+
return this[name]() // please note 'this[name]' is a accessor function with reactivity.
77+
},
78+
},
79+
}
80+
```
81+
82+
Node: the bound property is a **function** that returns the injected value, which follows the same rule as in `Consumer`. You can still expect to receive the `defaultValue` in case have no `Provider` being traced.
5683

5784
## 💎 Example
5885

@@ -64,6 +91,7 @@ For people using the SFC format, here is an conceptual example.
6491

6592
```js
6693
import { createContext } from 'vue-create-context';
94+
6795
export const CurrentUserContext = createContext({ firstName: 'Null', lastName: 'Unknown' });
6896
```
6997

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-create-context",
3-
"version": "1.0.2",
3+
"version": "1.1.0",
44
"description": "An abstracted util factory for creating scoped, declarative, and reactive context-components in Vue.",
55
"keywords": [
66
"vue"

src/index.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@ import { Component } from 'vue';
33
type createContext = (defaultValue: unknown) => { Provider: Component; Consumer: Component };
44

55
export const createContext: createContext = (defaultValue) => {
6-
const key = `_${Date.now()}${Math.random()}`;
6+
const _key = `_${Date.now()}${Math.random()}`;
7+
const _context = {
8+
from: _key,
9+
default: () => () =>
10+
defaultValue instanceof Object ? { ...defaultValue } : { value: defaultValue },
11+
};
12+
713
return {
814
Provider: {
915
name: 'Context.Provider',
1016
props: ['value'],
1117
provide(this: any) {
12-
return { [key]: () => this.value };
18+
return { [_key]: () => this.value };
1319
},
1420
render(this: any) {
1521
return this.$slots.default;
@@ -19,13 +25,10 @@ export const createContext: createContext = (defaultValue) => {
1925
name: 'Context.Consumer',
2026
functional: true,
2127
inject: {
22-
value: {
23-
from: key,
24-
default: () => () =>
25-
defaultValue instanceof Object ? { ...defaultValue } : { value: defaultValue },
26-
},
28+
value: _context,
2729
},
2830
render: (h, contexts: any) => contexts.scopedSlots.default(contexts.injections.value()),
2931
},
32+
_context,
3033
};
3134
};

0 commit comments

Comments
 (0)