将 `v-model` 的更改封装在 `$patch` 中

huangapple go评论60阅读模式
英文:

Wrap v-model changes in a $patch

问题

I need to wrap v-model changes in a $patch. I am using vue3 and pinia, and have a working solution, but wondering if there is a better way to do this.

My current working pattern is:

<script setup lang="ts">
 someAttribute = computed({
    get() {
        return store.someAttribute;
    },
    set(val: string) {
        store.$patch(() => {
            store.someAttribute = val;
        });
    },
});
</script>
<template>
<input v-model="store.someAttribute" />

</template>

This does appear to work, but is a bit annoying to do for every single attribute that I'm going to bind with v-model.

I need this behavior because I have code that subscribes to store changes. If there are dependencies to someAttribute, then this triggers multiple change events. With the $patch there is only one. I need there to be one event per user action since the other code is maintaining a history of the application state.

英文:

I need to wrap v-model changes in a $patch. I am using vue3 and pinia, and have a working solution, but wondering if there is a better way to do this.

My current working pattern is:

&lt;script setup lang=&quot;ts&quot;&gt;
 someAttribute = computed({
    get() {
        return store.someAttribute;
    },
    set(val: string) {
        store.$patch(() =&gt; {
            store.someAttribute = val;
        });
    },
});
&lt;/script&gt;
&lt;template&gt;
&lt;input v-model=&quot;store.someAttribute&quot; /&gt;

&lt;/template&gt;

This does appear to work, but is a bit annoying to do for every single attribute that I'm going to bind with v-model.

I need this behavior because I have code that subscribes to store changes. If there are dependencies to someAttribute, then this triggers multiple change events. With the $patch there is ony one. I need there to be one event per user action since the other code is maintaining a history of the application state.

答案1

得分: 2

> I need to wrap v-model changes in a $patch.

实际上,你不需要这样做。
状态属性和getter可以使用piniastoreToRefs函数提取为ref
使用refv-model建立了存储状态和输入值之间的双向绑定。

查看它的工作原理:

<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/vue-demi"></script>
<script src="https://unpkg.com/pinia@2.0.11/dist/pinia.iife.prod.js"></script>
<div id="app">
  <input v-model="foo" />
  <pre v-text="{ reversedFoo }" />
</div>

在你的情况中:

<script setup lang="ts">
import { storeToRefs } from "pinia"
//...
const { someAttribute } = storeToRefs(store)
</script>
<template>
  <input v-model="someAttribute" />
</template>

也可以在<template>中完成,但在我看来不够简洁:

<input v-model="storeToRefs(store).someAttribute">

重要提示:

只有stategetters存储成员应通过storeToRefs进行提取,而不是actions

以下是典型的存储使用示例:

<script setup>
//...
const { stateProp1, stateProp2, getter1, getter2 } = storeToRefs(store)
const { action1, action2 } = store

// 所有提取的存储成员现在已准备好在<template />中使用

// storeToRefs返回的是refs,可以在setup()中使用:
stateProp1.value = 'whatever';
</script>
英文:

> I need to wrap v-model changes in a $patch.

Actually, you don't.
State properties and getters can be extracted to refs using storeToRefs from pinia.
Using ref with v-model establishes a 2-way binding between the store's state and the input's value.

See it working:

<!-- begin snippet: js hide: true console: true babel: false -->

<!-- language: lang-js -->

const { createApp } = Vue
const { defineStore, createPinia, storeToRefs } = Pinia

const useStore = defineStore(&quot;pokemon&quot;, {
  state: () =&gt; ({ foo: &quot;ledom-v htiw etats ainip&quot; }),
  getters: {
    reversedFoo() {
      return this.foo.split(&quot;&quot;).reverse().join(&quot;&quot;)
    }
  }
})

createApp({ setup: () =&gt; storeToRefs(useStore()) })
  .use(createPinia())
  .mount(&quot;#app&quot;)

<!-- language: lang-html -->

&lt;script src=&quot;https://unpkg.com/vue@3/dist/vue.global.prod.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://unpkg.com/vue-demi&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://unpkg.com/pinia@2.0.11/dist/pinia.iife.prod.js&quot;&gt;&lt;/script&gt;
&lt;div id=&quot;app&quot;&gt;
  &lt;input v-model=&quot;foo&quot; /&gt;
  &lt;pre v-text=&quot;{ reversedFoo }&quot; /&gt;
&lt;/div&gt;

<!-- end snippet -->

In your case:

&lt;script setup lang=&quot;ts&quot;&gt;
import { storeToRefs } from &quot;pinia&quot;
//...
const { someAttribute } = storeToRefs(store)
&lt;/script&gt;
&lt;template&gt;
  &lt;input v-model=&quot;someAttribute&quot; /&gt;
&lt;/template&gt;

It can also be done in &lt;template&gt;, but it's not as neat, IMHO:

&lt;input v-model=&quot;storeToRefs(store).someAttribute&quot;&gt;

Important note:

Only state and getters store members should be extracted through storeToRefs. Not actions.

Here's a typical store usage:

&lt;script setup&gt;
//...
const { stateProp1, stateProp2, getter1, getter2 } = storeToRefs(store)
const { action1, action2 } = store

// all extracted store members are now ready for `&lt;template /&gt;` usage

// storeToRefs returns refs, usable in `setup()` as:
stateProp1.value = &#39;whatever&#39;

&lt;/script&gt;

huangapple
  • 本文由 发表于 2023年3月4日 07:14:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75632617.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定