サンプルアプリを作成している中で50枚ほどの画像を動的に表示する必要があり、その都度読み込んでいては遅いのでアプリの初回読み込み時に並列処理でVuexに持たせておくことにしました。
画像の並列処理と、このサンプルアプリ作成で初めてVuexを使用したので、そのアウトプットも兼ねて書いていきます。
環境
Vue 3.2.47
vuex 4.0.2
vite 4.2.0
node 16.13.0
App.vueでactionsを呼び出す
onMountedでvuexのactionsを呼び出します。
App.vue
<script setup lang="ts">
import { onMounted } from 'vue';
import { useStore } from 'vuex';
onMounted(async () => {
const store = useStore();
await store.dispatch('initializeCardImageList');
});
</script>
Vuexの実装
vuexはこのようになりました。
cardImageListというのが画像データを保持する変数になります。
actionsでinitializeCardImagesメソッドを呼び出し、戻り値をmutationに渡しています。
store/index.js
import { createStore } from 'vuex';
import { initializeCardImages } from '../utils/index';
type State = {
cardImageList: Record<number, string>; // 画像データが入る
};
const store = createStore<State>({
state: {
cardImageList: {},
},
mutations: {
setCardImageList(state, data) {
state.cardImageList = data; // stateに格納
},
},
actions: {
initializeCardImageList({ commit }) {
const cardImageList = initializeCardImages(); // このメソッド内で画像を並列処理で読み込む
commit('setCardImageList', cardImageList); // mutationを呼び出す
},
},
getters: {
getCardImageList(state) {
return state.cardImageList;
},
},
});
export default store;
画像を並列処理で読み込む
本題の並列処理になります。
utils/index.js
export const initializeCardImages = (): Record<string, HTMLImageElement> => {
// cardImageListにはオブジェクト形式でインポートした画像データが入っている
// { 1: image1, 2: image2, 3: image3 ... }
const promises = Object.values(cardImageList).map((url) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`Failed to load image ${url}`));
img.src = url;
});
});
const imageCache: Record<string, HTMLImageElement> = {};
Promise.all(promises).then((images) => {
images.forEach((img, i) => (imageCache[i] = img as HTMLImageElement));
});
return imageCache;
};
まとめ
今回はアプリの初回読み込み時に画像データを並列処理で読み込む方法をまとめました。
現状の実装では最初にまとめて行っているだけで、読み込み処理自体の長さはそこまで改善されていないので、画像を圧縮させたりして読み込み時間の短縮もいずれ行おうと思います。