Skip to content

Commit 64c8578

Browse files
author
Leo Y. Li
committed
#0: release v1.0.1
1 parent 99c7403 commit 64c8578

File tree

5 files changed

+83
-50
lines changed

5 files changed

+83
-50
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
---
77

8+
## [1.0.1] - 2019-04-26
9+
10+
## Improvement
11+
12+
- Simplify implementation.
13+
814
## [1.0.0] - 2019-04-25
915

1016
## Feature

README.md

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
[![npm version](https://badge.fury.io/js/vue-create-context.svg)](https://badge.fury.io/js/vue-create-context)
44

5-
An abstracted util factory for creating declarative and reactive contexts component in Vue. This API abstraction is greatly inspired by [`React.createContexts`](https://reactjs.org/docs/context.html#reactcreatecontext). The usage and its behaviour is exactly the same as you may expect if you already familiar with React. Under the hood, it uses Vue's reactive system with its `provide/inject` and scoped-slot API. It is light weight, declarative, and easy to use.
5+
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

77
## 🧰 Requirements
88

9-
This library requires Vue 2.6+, where Vue introduces the `v-slot` derivative, opening a new declarative pattern for passing component props in a compositional manner.
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.
1010

1111
## 🎬 Getting started
1212

1313
To get it started, add this package into your project:
1414

1515
```bash
16-
yarn add -D vue-create-context
16+
yarn add vue-create-context
1717
```
1818

1919
## 📔 API
@@ -25,17 +25,17 @@ import { createContext } from 'vue-create-context';
2525
const MyContext = createContext(defaultValue);
2626
```
2727

28-
Calling `createContext` with the `defaultValue` to create a context object. The `defaultValue` can be either a reference object or primitive, which is **ONLY** used when the `Consumer` component can not find its paired `Provider` above the rendering tree. The behaviour is the same as the one in React, so you can also have a look at [React.createContext](https://reactjs.org/docs/context.html#reactcreatecontext).
28+
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.
2929

3030
### `Context.Provider`
3131

3232
```vue
33-
<MyContext.Provider :value={/* the provided value */}>
33+
<MyContext.Provider value={/* the provided value */}>
3434
```
3535

36-
The `Provider` accept a `value` prop to be any value you want it to pass down the rendering tree. Similar to React, you can use this component multiple times an any level of the rendering tree. Its conjugated `Consumer` will receive the value from the closest `Provider` among its ancestors.
36+
The `Provider` accept a `value` prop to be any value you want it to pass down the rendering tree. Similar to React, you can use this component multiple times an any level of the tree. Its conjugated `Consumer` will receive the value from the closest `Provider` among its ancestors.
3737

38-
Note: If the provided value is reactive, update this value "reactively" will also update all its subscribed descended `Consumers`.
38+
Note: If the provided value is reactive, update this value "reactively" will also update all its subscribed descended `Consumers`. Also, make the value `undefined` (either explicitly passed in or implicitly set to) **WON'T** letting `Consumer` to use the `defaultValue`, which is the same as in React.
3939

4040
### `Context.Consumer`
4141

@@ -45,48 +45,86 @@ Note: If the provided value is reactive, update this value "reactively" will als
4545
</MyContext.Consumer>
4646
```
4747

48-
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 page](https://vuejs.org/v2/guide/components-slots.html#Destructuring-Slot-Props)).
48+
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)).
4949

50-
It is worth to mention that due to the current limitation 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 */ }`.
50+
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 */ }`.
5151

52-
Note. You might be tempted to mutate the injected value from the consumer. This is a bad idea since it violate the "[props down event up principle](https://vuejs.org/v2/style-guide/#Implicit-parent-child-communication-use-with-caution)". Under the hood, the library leverage the `computed` property in the `Consumer`, and you would not able to update/mutate on the source value. This is also consistent with the behaviour of Vue's `provide/inject` API.
52+
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.
5353

5454
## 💎 Example
5555

56-
There is an example in [the Official Storybook Vue](https://storybooks-vue.netlify.com/?path=/story/addon-contexts--languages) as an example of the `createContexts`.
56+
There is a story in [the Official Storybook Vue](https://monorepo-git-add-addon-contextsvue-i.storybook.now.sh/examples/vue-kitchen-sink/?path=/story/addon-contexts--languages) as an example of the `createContexts`.
5757

58-
For people using the SFC format, here is an conceptual example:
58+
For people using the SFC format, here is an conceptual example.
59+
60+
#### SomeContext.js
61+
62+
```js
63+
import { createContext } from 'vue-create-context';
64+
export const CurrentUserContext = createContext({ firstName: 'Null', lastName: 'Unknown' });
65+
```
66+
67+
#### SomeComponent.vue
5968

6069
```vue
6170
<template>
6271
<div>
63-
<Provider :value="currentUser">
64-
<Consumer v-slot="{ firstName, lastName }">
65-
<p>Hello {{ lastName }}, {{ firstName }}!</p>
66-
<!-- Hello Newman, Jack! -->
67-
</Consumer>
68-
</Provider>
72+
<!-- ... -->
6973
<Consumer v-slot="{ firstName, lastName }">
70-
<p>Hello {{ firstName }}, {{ lastName }}!</p>
71-
<!-- Hello N/A, N/A! -->
74+
<!-- Do something, where firstName, lastName is destructured from the received value -->
7275
</Consumer>
76+
<!-- ... -->
7377
</div>
7478
</template>
7579
7680
<script>
77-
import { createContext } from 'vue-create-context';
78-
const userContext = createContext({ firstName: 'N/A', lastName: 'N/A' }); // normally it is imported from other files.
81+
import { Consumer } from './SomeContext';
82+
83+
module.exports = {
84+
name: 'SomeComponent',
85+
components: {
86+
Consumer,
87+
},
88+
};
89+
</script>
90+
```
91+
92+
#### App.vue
93+
94+
```vue
95+
<template>
96+
<div>
97+
<Provider :value="user">
98+
<div>
99+
<SomeComponent />
100+
<!-- Consumer in the above component get { firstName: 'Jack', lastName: 'Newman' } -->
101+
<Provider value="{ firstName: 'Amy', lastName: 'Smith' }">
102+
<SomeComponent />
103+
<!-- Consumer in the above component get { firstName: 'Amy', lastName: 'Smith' } -->
104+
</Provider>
105+
</div>
106+
</Provider>
107+
<SomeComponent />
108+
<!-- Consumer in the above component get { firstName: 'Null', lastName: 'Unknown' } -->
109+
</div>
110+
</template>
111+
112+
<script>
113+
import { Provider } from './SomeContext';
114+
import SomeComponent from './SomeComponent';
79115
80116
module.exports = {
81-
name: 'MyComponent',
117+
name: 'App',
82118
components: {
83-
Provider: userContext.Provider,
84-
Consumer: userContext.Consumer,
119+
Provider,
120+
SomeComponent,
85121
},
86122
data() {
87123
return {
88-
firstName: 'Jack',
89-
lastName: 'Newman',
124+
user: {
125+
firstName: 'Jack',
126+
lastName: 'Newman',
127+
},
90128
};
91129
},
92130
};

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vue-create-context",
3-
"version": "1.0.0",
4-
"description": "An abstracted util factory for creating declarative and reactive contexts component in Vue.",
3+
"version": "1.0.1",
4+
"description": "An abstracted util factory for creating scoped, declarative, and reactive context-components in Vue.",
55
"keywords": [
66
"vue"
77
],
@@ -16,8 +16,8 @@
1616
"build": "babel src --out-dir dist --extensions \".ts,.tsx\"",
1717
"prepare": "yarn type:emit && yarn build"
1818
},
19-
"main": "index.js",
20-
"types": "index.d.ts",
19+
"main": "dist/index.js",
20+
"types": "dist/index.d.ts",
2121
"repository": "https://github.com/leoyli/vue-create-context.git",
2222
"author": "Leo Y. Li",
2323
"license": "MIT",
@@ -27,6 +27,7 @@
2727
"@babel/preset-env": "7.4.3",
2828
"@babel/preset-typescript": "7.3.3",
2929
"prettier": "1.17.0",
30-
"typescript": "3.4.5"
30+
"typescript": "3.4.5",
31+
"vue": "2.6.10"
3132
}
3233
}

src/index.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,23 @@ export const createContext: createContext = (defaultValue) => {
99
name: 'Context.Provider',
1010
props: ['value'],
1111
provide(this: any) {
12-
return this.value === undefined ? undefined : { [key]: () => this.value };
12+
return { [key]: () => this.value };
1313
},
1414
render(this: any) {
1515
return this.$slots.default;
1616
},
1717
},
1818
Consumer: {
1919
name: 'Context.Consumer',
20+
functional: true,
2021
inject: {
21-
[key]: {
22+
value: {
23+
from: key,
2224
default: () => () =>
2325
defaultValue instanceof Object ? { ...defaultValue } : { value: defaultValue },
2426
},
2527
},
26-
computed: {
27-
value(this: any) {
28-
return this[key]();
29-
},
30-
},
31-
render(this: any) {
32-
return this.$scopedSlots.default(this.value);
33-
},
28+
render: (h, contexts: any) => contexts.scopedSlots.default(contexts.injections.value()),
3429
},
3530
};
3631
};

yarn.lock

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -658,13 +658,6 @@
658658
lodash "^4.17.11"
659659
to-fast-properties "^2.0.0"
660660

661-
"@types/vue@2.0.0":
662-
version "2.0.0"
663-
resolved "https://registry.yarnpkg.com/@types/vue/-/vue-2.0.0.tgz#ec77b3d89591deb9ca5cb052368aa9c32be088e7"
664-
integrity sha1-7Hez2JWR3rnKXLBSNoqpwyvgiOc=
665-
dependencies:
666-
vue "*"
667-
668661
abbrev@1:
669662
version "1.1.1"
670663
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@@ -2154,7 +2147,7 @@ util-deprecate@~1.0.1:
21542147
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
21552148
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
21562149

2157-
vue@*:
2150+
vue@2.6.10:
21582151
version "2.6.10"
21592152
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
21602153
integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==

0 commit comments

Comments
 (0)