Skip to content

[pull] indonesian from master #240

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

Merged
merged 2 commits into from
Aug 10, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
51 changes: 43 additions & 8 deletions src/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const sidebar = {
title: 'Petunjuk lebih Lanjut',
collapsable: false,
children: [
'/guide/web-components',
{
title: 'Reaktivitas',
children: [
Expand All @@ -106,7 +107,12 @@ const sidebar = {
{
title: 'Peningkatan',
collapsable: false,
children: ['/guide/routing', '/guide/state-management', '/guide/ssr', '/guide/security']
children: [
'/guide/routing',
'/guide/state-management',
'/guide/ssr',
'/guide/security'
]
},
{
title: 'Aksesibilitas',
Expand Down Expand Up @@ -148,10 +154,33 @@ const sidebar = {
children: [
'/api/basic-reactivity',
'/api/refs-api',
'/api/computed-watch-api'
'/api/computed-watch-api',
'/api/effect-scope',
]
},
'/api/composition-api'
'/api/composition-api',
{
title: 'Single File Components',
collapsable: false,
children: [
{
title: 'Spec',
path: '/api/sfc-spec'
},
{
title: 'Tooling',
path: '/api/sfc-tooling'
},
{
title: '<script setup>',
path: '/api/sfc-script-setup'
},
{
title: '<style> Features',
path: '/api/sfc-style'
}
]
}
],
examples: [
{
Expand Down Expand Up @@ -379,8 +408,7 @@ module.exports = {
},
{
text: 'Vue Test Utils',
link:
'https://next.vue-test-utils.vuejs.org/guide/'
link: 'https://next.vue-test-utils.vuejs.org/guide/'
},
{
text: 'Devtools',
Expand Down Expand Up @@ -495,11 +523,18 @@ module.exports = {
const date = new Date(timestamp)

const digits = [
date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate(),
date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()
date.getUTCFullYear(),
date.getUTCMonth() + 1,
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds()
].map(num => String(num).padStart(2, '0'))

return '{0}-{1}-{2}, {3}:{4}:{5} UTC'.replace(/{(\d)}/g, (_, num) => digits[num])
return '{0}-{1}-{2}, {3}:{4}:{5} UTC'.replace(
/{(\d)}/g,
(_, num) => digits[num]
)
}
}
],
Expand Down
35 changes: 32 additions & 3 deletions src/api/computed-watch-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,31 @@ console.log(count.value) // 0

```ts
// read-only
function computed<T>(getter: () => T): Readonly<Ref<Readonly<T>>>
function computed<T>(
getter: () => T,
debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>

// writable
function computed<T>(options: { get: () => T; set: (value: T) => void }): Ref<T>
function computed<T>(
options: {
get: () => T
set: (value: T) => void
},
debuggerOptions?: DebuggerOptions
): Ref<T>

interface DebuggerOptions {
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}

interface DebuggerEvent {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
}
```

## `watchEffect`
Expand Down Expand Up @@ -84,9 +105,17 @@ type StopHandle = () => void

**See also**: [`watchEffect` guide](../guide/reactivity-computed-watchers.html#watcheffect)

## `watchPostEffect` <Badge text="3.2+" />

Alias of `watchEffect` with `flush: 'post'` option.

## `watchSyncEffect` <Badge text="3.2+" />

Alias of `watchEffect` with `flush: 'sync'` option.

## `watch`

The `watch` API is the exact equivalent of the Options API [this.$watch](./instance-methods.html#watch) (and the corresponding [watch](./options-data.html#watch) option). `watch` requires watching a specific data source and applies side effects in a separate callback function. It also is lazy by default - i.e. the callback is only called when the watched source has changed.
The `watch` API is the exact equivalent of the Options API [this.\$watch](./instance-methods.html#watch) (and the corresponding [watch](./options-data.html#watch) option). `watch` requires watching a specific data source and applies side effects in a separate callback function. It also is lazy by default - i.e. the callback is only called when the watched source has changed.

- Compared to [watchEffect](#watcheffect), `watch` allows us to:

Expand Down
84 changes: 70 additions & 14 deletions src/api/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@

## v-bind

- **Shorthand:** `:`
- **Shorthand:** `:` or `.` (when using `.prop` modifier)

- **Expects:** `any (with argument) | Object (without argument)`

Expand All @@ -246,6 +246,8 @@
- **Modifiers:**

- `.camel` - transform the kebab-case attribute name into camelCase.
- `.prop` - force a binding to be set as a DOM property. <Badge text="3.2+"/>
- `.attr` - force a binding to be set as a DOM attribute. <Badge text="3.2+"/>

- **Usage:**

Expand Down Expand Up @@ -278,23 +280,34 @@
<!-- class binding -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]">
<!-- style binding -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]"></div>

<!-- binding an object of attributes -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
<!-- style binding -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>

<!-- prop binding. "prop" must be declared in my-component. -->
<my-component :prop="someThing"></my-component>
<!-- binding an object of attributes -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

<!-- pass down parent props in common with a child component -->
<child-component v-bind="$props"></child-component>
<!-- prop binding. "prop" must be declared in my-component. -->
<my-component :prop="someThing"></my-component>

<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
</div>
<!-- pass down parent props in common with a child component -->
<child-component v-bind="$props"></child-component>

<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
```

When setting a binding on an element, Vue by default checks whether the element has the key defined as a property using an `in` operator check. If the property is defined, Vue will set the value as a DOM property instead of an attribute. This should work in most cases, but you can override this behavior by explicitly using `.prop` or `.attr` modifiers. This is sometimes necessary, especially when [working with custom elements](/guide/web-components.html#passing-dom-properties).

The `.prop` modifier also has a dedicated shorthand, `.`:

```html
<div :someProperty.prop="someObject"></div>

<!-- equivalent to -->
<div .someProperty="someObject"></div>
```

The `.camel` modifier allows camelizing a `v-bind` attribute name when using in-DOM templates, e.g. the SVG `viewBox` attribute:
Expand Down Expand Up @@ -451,8 +464,51 @@
</ul>
```

Since 3.2, you can also memoize part of the template with invalidation conditions using [`v-memo`](#v-memo).

- **See also:**
- [Data Binding Syntax - interpolations](../guide/template-syntax.html#text)
- [v-memo](#v-memo)

## v-memo <Badge text="3.2+" />

- **Expects:** `Array`

- **Details:**

Memoize a sub-tree of the template. Can be used on both elements and components. The directive expects a fixed-length array of dependency values to compare for the memoization. If every value in the array was the same as last render, then updates for the entire sub-tree will be skipped. For example:

```html
<div v-memo="[valueA, valueB]">
...
</div>
```

When the component re-renders, if both `valueA` and `valueB` remain the same, all updates for this `<div>` and its children will be skipped. In fact, even the Virtual DOM VNode creation will also be skipped since the memoized copy of the sub-tree can be reused.

It is important to specify the memoization array correctly, otherwise we may skip updates that should indeed be applied. `v-memo` with an empty dependency array (`v-memo="[]"`) would be functionally equivalent to `v-once`.

**Usage with `v-for`**

`v-memo` is provided solely for micro optimizations in performance-critical scenarios and should be rarely needed. The most common case where this may prove helpful is when rendering large `v-for` lists (where `length > 1000`):

```html
<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
<p>ID: {{ item.id }} - selected: {{ item.id === selected }}</p>
<p>...more child nodes</p>
</div>
```

When the component's `selected` state changes, a large amount of VNodes will be created even though most of the items remained exactly the same. The `v-memo` usage here is essentially saying "only update this item if it went from non-selected to selected, or the other way around". This allows every unaffected item to reuse its previous VNode and skip diffing entirely. Note we don't need to include `item.id` in the memo dependency array here since Vue automatically infers it from the item's `:key`.

:::warning
When using `v-memo` with `v-for`, make sure they are used on the same element. **`v-memo` does not work inside `v-for`.**
:::

`v-memo` can also be used on components to manually prevent unwanted updates in certain edge cases where the child component update check has been de-optimized. But again, it is the developer's responsibility to specify correct dependency arrays to avoid skipping necessary updates.

- **See also:**
- [v-once](#v-once)

## v-is <Badge text="deprecated" type="warning" />

Expand Down
59 changes: 59 additions & 0 deletions src/api/effect-scope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Effect Scope API <Badge text="3.2+" />

:::info
Effect scope is an advanced API primarily intended for library authors. For details on how to leverage this API, please consult its corresponding [RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md).
:::

## `effectScope`

Creates an effect scope object which can capture the reactive effects (e.g. computed and watchers) created within it so that these effects can be disposed together.

**Typing:**

```ts
function effectScope(detached?: boolean): EffectScope

interface EffectScope {
run<T>(fn: () => T): T | undefined // undefined if scope is inactive
stop(): void
}
```

**Example:**

```js
const scope = effectScope()

scope.run(() => {
const doubled = computed(() => counter.value * 2)

watch(doubled, () => console.log(doubled.value))

watchEffect(() => console.log('Count: ', doubled.value))
})

// to dispose all effects in the scope
scope.stop()
```

## `getCurrentScope`

Returns the current active [effect scope](#effectscope) if there is one.

**Typing:**

```ts
function getCurrentScope(): EffectScope | undefined
```

## `onScopeDispose`

Registers a dispose callback on the current active [effect scope](#effectscope). The callback will be invoked when the associated effect scope is stopped.

This method can be used as a non-component-coupled replacement of `onUnmounted` in reusable composition functions, since each Vue component's `setup()` function is also invoked in an effect scope.

**Typing:**

```ts
function onScopeDispose(fn: () => void): void
```
Loading