ホームページ >ウェブフロントエンド >jsチュートリアル >知っておくべき Vue コンポーザブルのヒント
Vue コンポーザブルは非常に強力ですが、注意しないとすぐに乱雑になり、保守が困難になる可能性があります。
そのため、より優れた、より保守しやすいコンポーザブルを作成するのに役立つ 13 のヒントを特定しました。
単純な状態管理ソリューションを構築している場合でも、複雑な共有ロジックを構築している場合でも、以下のヒントが役に立ちます。
あなたが学ぶヒントは次のとおりです:
各パターンを詳しく見て、Vue アプリケーションをどのように改善できるかを見てみましょう。
そして、お気に入りのヒントを下にコメントすることを忘れないでください!
データ ストア パターンは、複数のコンポーネント レイヤーを介してプロパティやイベントを渡すことを回避するのに役立ちます。
1 つの状況は、無限のプロップドリルとイベントバブリングを通じて親子が通信している場合です。
<!-- Parent.vue --> <template> <!-- But many more layers of components --> <Child :user="user" @change="onUserChange" /> </template> <script setup> const user = ref({ name: 'Alice' }) function onUserChange(updatedUser) { user.value = updatedUser } </script>
これらのプロパティとイベントはコンポーネント階層内を行き来する必要があるため、非常に複雑になります。
より簡単な解決策は、任意のコンポーネントがインポートできる共有データ ストアを作成することです。
import { reactive, toRefs } from 'vue' const state = reactive({ user: { name: 'Alice' } }) export function useUserStore() { return toRefs(state) }
データ ストア パターンは、兄弟または「いとこ」コンポーネントが直接接続せずに同じデータを共有する必要がある場合にも役立ちます。
2 人の兄弟がどちらも同じユーザー オブジェクトを必要としているとします。しかし、プロップやイベントのためのエレガントなパスがありません。
これにより、多くの場合、親または重複した状態を介してデータを扱いにくくすることになります。
より良いアプローチは、両方の兄弟が利用できる単一のコンポーザブル ストアに依存することです。
// SiblingA.vue import { useUserStore } from './useUserStore' const { user } = useUserStore() // SiblingB.vue import { useUserStore } from './useUserStore' const { user } = useUserStore()
データ ストア パターンは、共有状態を更新するための明確な方法を提供することを奨励します。
開発者の中には、次のようにリアクティブ オブジェクト全体を世界に公開する人もいます。
<!-- Parent.vue --> <template> <!-- But many more layers of components --> <Child :user="user" @change="onUserChange" /> </template> <script setup> const user = ref({ name: 'Alice' }) function onUserChange(updatedUser) { user.value = updatedUser } </script>
これにより、誰でも任意のファイルからユーザーの darkMode プロパティを直接変更できるようになり、分散した制御不能な変異が発生する可能性があります。
より良いアイデアは、更新がどのように行われるかを定義する関数とともに読み取り専用として状態を返すことです。
import { reactive, toRefs } from 'vue' const state = reactive({ user: { name: 'Alice' } }) export function useUserStore() { return toRefs(state) }
インライン コンポーザブル パターンは、関連する状態とロジックを小さな関数に収集することで、大きなコンポーネントを分割するのに役立ちます。
巨大なコンポーネントでは、そのすべての参照とメソッドが 1 か所に配置される場合があります。
// SiblingA.vue import { useUserStore } from './useUserStore' const { user } = useUserStore() // SiblingB.vue import { useUserStore } from './useUserStore' const { user } = useUserStore()
そのセットアップはすぐに管理できなくなります。
代わりに、インライン コンポーザブルはロジックをグループ化し、ローカルに提供できます。後でそれを別のファイルに抽出できます:
export const user = reactive({ darkMode: false })
Thin Composables パターンは、生のビジネス ロジックを Vue の反応性から分離することを指示し、テストとメンテナンスが簡素化されます。
すべてのロジックをコンポーザブルに埋め込むことができます:
import { reactive, readonly } from 'vue' const state = reactive({ darkMode: false }) export function toggleDarkMode() { state.darkMode = !state.darkMode } export function useUserStore() { return { darkMode: readonly(state.darkMode), toggleDarkMode } }
これにより、Vue 環境内でロジックをテストする必要があります。
代わりに、複雑なルールを純粋な関数に保持し、コンポーザブルでリアクティブ ラッパーのみを処理できるようにします。
<script setup> const count = ref(0) const user = ref({ name: 'Alice' }) // 500 more lines of intertwined code with watchers, methods, etc. </script>
Async Sync コンポーザブル パターンは、個別の関数を作成するのではなく、同期動作と非同期動作の両方を 1 つのコンポーザブルにマージします。
これは、Nuxt の useAsyncData の仕組みとまったく同じです。
ここには、Promise を返すと同時に、同期使用のための即時リアクティブ プロパティも提供できる単一のコンポーザブルがあります。
<script setup> function useCounter() { const count = ref(0) const increment = () => count.value++ return { count, increment } } const { count, increment } = useCounter() </script>
オプション オブジェクト パターンは、単一の構成オブジェクトを期待することでパラメータの長いリストを整理できます。
このような呼び出しは面倒で間違いが発生しやすく、新しいオプションを追加するには関数シグネチャを更新する必要があります。
export function useCounter() { const count = ref(0) function increment() { count.value = (count.value * 3) / 2 } return { count, increment } }
それぞれの引数が何を意味するのかは明らかではありません。
オプション オブジェクトを受け入れるコンポーザブルは、すべてを説明的に保ちます。
// counterLogic.js export function incrementCount(num) { return (num * 3) / 2 } // useCounter.js import { ref } from 'vue' import { incrementCount } from './counterLogic' export function useCounter() { const count = ref(0) function increment() { count.value = incrementCount(count.value) } return { count, increment } }
オプション オブジェクト パターンでは、各プロパティのデフォルト値も推奨されています。
特定のフィールドが存在することを前提とする関数は、フィールドが渡されないと問題が発生する可能性があります:
import { ref } from 'vue' export function useAsyncOrSync() { const data = ref(null) const promise = fetch('/api') .then(res => res.json()) .then(json => { data.value = json return { data } }) return Object.assign(promise, { data }) }
安全なデフォルトを使用してオプションを構造化することをお勧めします:
useRefHistory(someRef, true, 10, 500, 'click', false)
動的リターン パターンにより、コンポーザブルは単純なユースケースでは単一の値を返すことも、より高度なコントロールを備えた展開されたオブジェクトを返すこともできます。
一部のアプローチは常にすべてを含むオブジェクトを返します:
<!-- Parent.vue --> <template> <!-- But many more layers of components --> <Child :user="user" @change="onUserChange" /> </template> <script setup> const user = ref({ name: 'Alice' }) function onUserChange(updatedUser) { user.value = updatedUser } </script>
メインのリアクティブ値のみを必要とする人は、余分なものを処理する必要があります。
条件付きで単一の参照またはオブジェクトを返すコンポーザブルは、次のことを解決します。
import { reactive, toRefs } from 'vue' const state = reactive({ user: { name: 'Alice' } }) export function useUserStore() { return toRefs(state) }
非表示のコンポーザブル パターンは、同じコンポーザブル内で相互排他的なロジックが混在することを避けるのに役立ちます。
一部のコードは複数のモードまたはコード パスをひとまとめにしています:
// SiblingA.vue import { useUserStore } from './useUserStore' const { user } = useUserStore() // SiblingB.vue import { useUserStore } from './useUserStore' const { user } = useUserStore()
各パスを独自のコンポーザブルに分割すると、より明確になり、機能には影響しません。
export const user = reactive({ darkMode: false })
柔軟な引数パターンにより、コンポーザブルの入力と出力がリアクティブ データまたは生の値として均一に処理され、混乱が回避されます。
一部のコードは、入力が参照であるかどうかをチェックします。
import { reactive, readonly } from 'vue' const state = reactive({ darkMode: false }) export function toggleDarkMode() { state.darkMode = !state.darkMode } export function useUserStore() { return { darkMode: readonly(state.darkMode), toggleDarkMode } }
代わりに、すぐに変換できます。
ref を使用すると、入力が ref の場合、その ref が返されます。それ以外の場合は、ref:
に変換されます。
<script setup> const count = ref(0) const user = ref({ name: 'Alice' }) // 500 more lines of intertwined code with watchers, methods, etc. </script>
柔軟な引数パターンは、ラップ解除が必要な場合にも toValue を使用します。
これがないと、コードは isRef チェックを実行し続ける可能性があります:
<script setup> function useCounter() { const count = ref(0) const increment = () => count.value++ return { count, increment } } const { count, increment } = useCounter() </script>
呼び出し方ははるかに簡単です:
export function useCounter() { const count = ref(0) function increment() { count.value = (count.value * 3) / 2 } return { count, increment } }
オプションから合成パターンへの移行により、大きなオプション API コンポーネントを段階的に簡単に段階的に合成 API に移行できます。
従来のオプション コンポーネントでは次のことが行われます。
// counterLogic.js export function incrementCount(num) { return (num * 3) / 2 } // useCounter.js import { ref } from 'vue' import { incrementCount } from './counterLogic' export function useCounter() { const count = ref(0) function increment() { count.value = incrementCount(count.value) } return { count, increment } }
データ、計算されたプロパティ、メソッドが分散しています。
これをスクリプト設定に変換すると、それらがまとめられて理解しやすくなり、次のパターンを使用できるようになります。
import { ref } from 'vue' export function useAsyncOrSync() { const data = ref(null) const promise = fetch('/api') .then(res => res.json()) .then(json => { data.value = json return { data } }) return Object.assign(promise, { data }) }
これらの 13 のヒントは、アプリケーション全体での保守、テスト、再利用が容易な、より優れた Vue コンポーザブルを作成するのに役立ちます。
しかし、ここでは表面をなぞっただけです。
何年にもわたって、私はさらに多くのパターンとヒントを収集し、それらをすべてコンポーザブル パターンに関する詳細なコースにまとめました。
合計 16 のパターンがカバーされており、各パターンには次の内容があります:
詳細については、ここにアクセスしてください。
ああ、このコースは 1 月 15 日までセール中なので、今なら大幅割引で購入できます!
コンポーザブルなデザインパターンをチェックしてください
以上が知っておくべき Vue コンポーザブルのヒントの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。