Store
Framework7には、軽量なアプリケーション状態管理ライブラリであるStoreが組み込まれています。これは、アプリケーション内のすべてのコンポーネントに対して集中化されたStoreとして機能します。
Vueの場合はVuex、Reactの場合はReduxのようなライブラリ固有の状態管理ライブラリを使用したり、組み込みのSvelteストア機能を使用したりできます。ただし、シンプルなものが要求される場合には、Framework7 Storeが適している可能性があります。
Storeの作成
まず最初に、Storeを作成する必要があります。そのために、別のstore.js
ファイルを作成しましょう。
// First import createStore function from Framework7 core
import { createStore } from 'framework7/lite';
// create store
const store = createStore({
// start with the state (store data)
state: {
users: [],
// ...
},
// actions to operate with state and for async manipulations
actions: {
// context object containing store state will be passed as an argument
getUsers({ state }) {
// fetch users from API
fetch('some-url')
.then((res) => res.json())
.then((users) => {
// assign new users to store state.users
state.users = users;
})
},
// ...
},
// getters to retrieve the state
getters: {
// context object containing store state will be passed as an argument
users({ state }) {
return state.users;
}
}
})
// export store
export default store;
この例では、次のAPI関数を使用しました。
createStore(storeParameters)- Storeを作成します
- storeParameters - オブジェクト。Storeパラメータを持つオブジェクト
メソッドは、作成されたStoreインスタンスを返します。
Storeパラメータ
次に、storeParameters
オブジェクトを見てみましょう。
State
state
は、アプリケーションレベルのすべての状態を含む単一のオブジェクトであり、「信頼できる唯一の情報源」として機能します。これは、通常、各アプリケーションに対して1つのストアしか持たないことを意味します。単一の状態ツリーにより、特定の状態を簡単に見つけることができ、デバッグ目的で現在のアプリの状態のスナップショットを簡単に取得できます。
アクション
actions
は、状態を変更したり、非同期操作を行ったり、他のストアアクションを呼び出したりするために使用されます。アクションハンドラーは、ストアの状態と他のアクションを呼び出すためのディスパッチメソッドを持つコンテキストオブジェクトを受け取ります。したがって、context.store
にアクセスして状態にアクセスしたり、context.dispatch
で他のアクションを呼び出したりできます。
2番目の引数として、アクションハンドラーは任意のカスタムデータを受け取ることができます。
Storeをリアクティブに保つには、代入によって状態を変更する必要があります。たとえば、次のようになります。
// modification of current state property - NOT REACTIVE
state.users.push(...users);
// assignemt to new value - REACTIVE
state.users = [...state.users, ...users];
ゲッター
getters
ハンドラーは、ストアの状態からデータを返すために使用されます。また、ストアの状態に基づいて派生状態を計算する必要がある場合(たとえば、アイテムのリストをフィルタリングする場合)にも便利です。
const store = createStore({
state: {
users: [
{ id: 1, name: '...', registered: true },
{ id: 2, name: '...', registered: false }
]
},
getters: {
registeredUsers: ({ state }) => {
return state.users.filter((user) => user.registered);
}
}
})
ゲッターハンドラーもコンテキストオブジェクトを受け取りますが、ストアの状態のみを受け取ります。たとえば、ゲッターから他のアクションを呼び出すことはできません。
Storeの使用
Storeを作成したので、その使い方を見ていきましょう。
まず最初に、作成したStoreをメインのAppコンポーネントに渡す必要があります。
<!-- pass store to the App's "store" prop -->
<App store={store}>
<View main>
<!-- ... -->
</View>
</App>
<script>
import { App, View } from 'framework7-svelte';
// import our store
import store from 'path/to/store.js';
</script>
StoreとStateへのアクセス
作成したStoreインスタンスを参照することで、Store(およびその状態)に直接アクセスできます。
import store from 'path/to/store.js';
console.log(store.state.users);
または、Framework7インスタンスのstore
プロパティにアクセスすることでアクセスできます。
import { f7 } from 'framework7-svelte';
console.log(f7.store.state.users);
アクションのディスパッチ
アクションを呼び出すには、呼び出すアクションの名前を指定してstore.dispatch
メソッドを呼び出す必要があります。
次のストアアクションがある場合
const store = createStore({
// ...
actions: {
// handler receives custom data in second argument
getUsers({ state }, { total }) {
fetch(`some-url?total=${total}`)
.then((res) => res.json())
.then((users) => {
state.users = users;
})
},
},
// ...
})
store.dispatch
メソッドを呼び出す必要があります。
import store from 'path/to/store.js';
// call 'getUsers' actions
store.dispatch('getUsers', { total: 10 })
アクションハンドラーで、別のアクションハンドラーを呼び出したい場合
const store = createStore({
// ...
actions: {
setLoading({ state }, isLoading) {
state.isLoading = isLoading;
},
// handler context also contains "dispatch" method
getUsers({ state, dispatch }, { total }) {
// call other action
dispatch('setLoading', true);
fetch(`some-url?total=${total}`)
.then((res) => res.json())
.then((users) => {
state.users = users;
// call other action
dispatch('setLoading', false);
})
},
},
// ...
});
ゲッター
ゲッターの値は、store.getters
オブジェクトの静的プロパティとしてアクセスできます。
const store = createStore({
state: {
count: 10,
},
getters: {
count({ state }) {
return state.count;
},
double({ state }) {
return state.count * 2;
},
},
});
import store from 'path/to/store.js';
const count = store.getters.count;
const double = store.getters.double;
ゲッターの値は、ゲッターハンドラーの結果を含む.value
プロパティを持つ静的オブジェクトであるため、次のようになります。
console.log(count.value); // -> 10
console.log(double.value); // -> 20
状態とは異なり、ゲッターはリアクティブになることを目的としています。したがって、リアクティビティが必要ない場合は、store.state
に直接アクセスできます。それ以外の場合は、ゲッターを使用してください。
Svelteコンポーネントでの使用
Svelteコンポーネントで使用してStoreをリアクティブに保つための特別なuseStore
ヘルパーがあります(状態/ゲッターの値が変更されたときにコンポーネントを自動更新します)。
useStore(getterName, callback)- ゲッター値を直接返し、状態の更新をサブスクライブします
- getterName - 文字列 - ゲッターハンドラーの名前
- callback - 関数 - 依存状態が変更されたときに新しいゲッター値で実行されるコールバック関数。
メソッドは、ゲッターハンドラーの値を返します。
別のStoreインスタンスからゲッター値を取得する必要がある場合は、Storeも渡す必要があります。
useStore(store, getterName, callback)- ゲッター値を直接返し、状態の更新をサブスクライブします
- store - Storeインスタンス - ゲッターを検索するStoreインスタンス。指定しない場合は、
<App>
コンポーネントに渡されるデフォルトのStoreが使用されます。 - getterName - 文字列 - ゲッターハンドラーの名前
- callback - 関数 - 依存状態が変更されたときに新しいゲッター値で実行されるコールバック関数。
メソッドは、ゲッターハンドラーの値を返します。
次のStoreがある場合
const store = createStore({
state: {
users: [],
},
actions: {
getUsers({ state }) {
// ...
},
},
getters: {
users({ state }) {
return state.users;
}
},
});
たとえば、Svelteコンポーネントで次のものを使用する必要があります。
<Page>
<List>
{#each users as user}
<ListItem title={user.name} />
{/each}
</List>
</Page>
<script>
import { onMount } from 'svelte';
// import special useStore helper/hook
import { useStore, Page, List, ListItem } from 'framework7-svelte';
// import store
import store from 'path/to/store.js'
// retrieve "users" getter handler value. Initially empty array
let users = useStore('users', (value) => users = value);
onMount(() => {
// load users when component mounted
store.dispatch('getUsers');
});
</script>
Framework7のuseStore
ヘルパー/フックを使用したため、ユーザーがロードされるとコンポーネントは自動的に更新されます。
例
import { createStore } from 'framework7/lite';
const store = createStore({
state: {
loading: false,
users: [],
},
actions: {
getUsers({ state }) {
state.loading = true;
setTimeout(() => {
state.users = ['User 1', 'User 2', 'User 3', 'User 4', 'User 5'];
state.loading = false;
}, 3000);
},
},
getters: {
loading({ state }) {
return state.loading;
},
users({ state }) {
return state.users;
},
},
});
export default store;
<script>
import {
f7,
useStore,
Page,
Navbar,
Block,
Button,
Preloader,
List,
ListItem,
} from 'framework7-svelte';
// Subscribe to store getters
let users = useStore('users', (value) => (users = value));
let loading = useStore('usersLoading', (value) => (loading = value));
// Call store action
const load = () => f7.store.dispatch('loadUsers');
</script>
<Page>
<Navbar title="Store" />
<Block strong>
<p>
Framework7 comes with a built-in lightweight application state management library - Store. It
serves as a centralized Store for all the components in an application.
</p>
</Block>
{#if !users}
<Block class="text-align-center">
{#if !loading}
<Button on:click={load} fill round>Load Users</Button>
{/if}
{#if loading}
<Preloader />
{/if}
</Block>
{/if}
{#if users}
<List strong outlineIos dividersIos insetMd>
{#each users as user}
<ListItem title={user} />
{/each}
</List>
{/if}
</Page>