동일한 이미지에서 불필요한 http 요청 방지 - vuejs
상황:
페이지에는 사용자 목록을 수신하는 여러 구성 요소가 있습니다.목록을 받은 후 사용자의 이미지를 가져오기 위해 추가 구성 요소를 호출하는 foreach 사이클이 있습니다.여러 구성 요소가 동일한 사용자를 포함할 수 있습니다. 즉, "반복된 이미지"를 가져오기 위해 동일한 http 요청을 반복해야 합니다.이러한 불필요한 요구를 피하기 위해 vueX 스토어에 특정 base64 이미지가 있는 사용자의 정보를 설정하여 이미지를 이미 받았는지 여부를 검증합니다.
문제:첫 번째 컴포넌트가 이미지 가져오기 및 스토어에 저장 요청을 했을 때 나머지 컴포넌트는 이미 작성되어 있기 때문에 스토어가 비어 있기 때문에 이미지가 있는지 확인할 수 없습니다.
솔루션:컴포넌트를 생성할 때 다음을 사용하여 스토어가 존재하도록 강제합니다.
this.images[this.user.id] = 'reserved';
하지만 이것이 이 상황에 대한 올바른 접근법인지 잘 모르겠습니다.제안 접수 :'D'
코드:
부모 성분
<template>
<div class="info-cards">
<div class="info-users">
<div class="info-label">{{ $t('global.users') }}</div>
<div class="info-images" v-if="users.length > 0">
<base-users-image
v-for="user in users"
:key="user.name"
:user="user"
/>
</div>
<div v-else class="message">{{ $t('global.noUsersRole') }}</div>
</div>
</div>
</template>
<script>
// import components
const baseUsersImage = () => System.import(/* webpackChunkName: 'usersImage' */ './../../users/baseUsersImage');
export default {
props: {
users: Array,
packages: Array
},
components: {
baseUsersImage: baseUsersImage
},
}
</script>
이미지 컴포넌트
<template>
<router-link to="user" class="anchor-image">
<img v-if="show" :src="image" :alt="user.name" class="image">
<div v-else class="image-default">t</div>
</router-link>
</template>
<script>
// import requests
import requests from './../../../helpers/requests.js';
// import store
import { mapGetters, mapActions } from 'vuex';
export default {
props: {
user: Object
},
data() {
return {
image: '',
show: false
}
},
created() {
if (this.user.avatar) { // check if user has avatar
if ( this.images[this.user.id] == null) { // check if it already exists in the store
this.images[this.user.id] = 'reserved'; // set as reserved in store
requests.get(this.user.avatar, { responseType: 'arraybuffer' }) // faz o pedido a API da image
.then( (response) => {
this.saveImage( { id: this.user.id, url: `data:${response.headers['content-type']};base64,${Buffer.from(response.data, 'binary').toString('base64')}` } );
}, error => {
console.log(error);
});
}
}
},
methods: {
...mapActions({
saveImage: 'saveImage'
})
},
computed: {
...mapGetters({
images: 'images'
})
},
watch: {
images: {
immediate: true,
deep: true, // so it detects changes to properties only
handler(newVal, oldVal) {
if ( newVal[this.user.id] !=='reserved'
&& this.user.avatar
&& newVal[this.user.id] !== undefined
) {
this.image = newVal[this.user.id];
this.show = true;
}
}
}
}
}
</script>
가게
const state = {
images: {}
}
const SAVE_IMAGE = (state, payload) => {
state.images = {
...state.images,
[payload.id] : payload.url
}
}
const saveImage = ({commit}, payload) => {
commit('SAVE_IMAGE', payload);
}
제가 할 일은 다음과 같습니다.
우선 모든 요청 로직을 VueX로 이동하고 컴포넌트를 최대한 단순하게 유지합니다.이것은, 다음의 몇개의 코드로 실현 가능합니다.
export default {
props: {
user: Object
},
created () {
if (this.user.avatar) {
this.$store.dispatch('fetchImage', this.user.avatar)
}
}
}
그럼 이 간단한 패턴으로 가게를 정리하겠습니다.먼저, 상태가 어떻게 표시되는지 살펴보겠습니다.
{
images: {
'/users/1/avatar': 'data:png:base64,....', // An image that have been loaded
'/users/2/avatar': null // An image that is supposed to be loading
}
}
보다시피images
object는 이미지 URL을 키로 사용하고 base64 데이터를 값으로 사용합니다.데이터 값이 null이면 이미지가 이미 로드 중임을 의미합니다.
이제 이를 처리하기 위한 작업을 어떻게 작성해야 하는지 알아보겠습니다.
const actions = {
fetchImage ({state, commit}, url) {
if (typeof state.images[url] !== 'undefined') {
return null
}
commit('setImage', {
url,
payload: null
})
return requests.get(url, { responseType: 'arraybuffer'}).then(response => {
commit('setImage', {
url,
payload: `data:${response.headers['content-type']};base64,${Buffer.from(response.data, 'binary').toString('base64')}`
})
})
}
}
첫 번째 조건을 보세요.이미지가 아닌 경우undefined
가게에서는 아무것도 하지 않아요.왜냐하면 이미지가 그렇지 않으면undefined
, 이것은, 어느쪽인가를 의미합니다.null
(로드) 또는 값이 있고 로드됩니다.
이 조건 직후에 이미지를null
다른 컴포넌트가 이미지를 로드하지 않도록 합니다.
마지막으로 이미지의 내용을 로드하여 상태에 커밋합니다.
이제 템플릿을 살펴보겠습니다.
<template>
<router-link to="user" class="anchor-image">
<img v-if="$store.state.images[user.avatar]" :src="$store.state.images[user.avatar]" :alt="user.name" class="image">
<div v-else class="image-default">t</div>
</router-link>
</template>
이미지를 표시해야 하는지 확인하려면v-if="$store.state.images[user.avatar]"
이미지가 로드되는 즉시 표시됩니다.
$store.state.images[user.avatar]
가 「라고 해도, .loading
에는 (이것)이 .null
discloss.discloss 。
도움이 됐으면 좋겠네요!
(이것이 전체 스토어입니다.)
const store = {
state: {
images: {}
},
mutations: {
setImage (state, image) {
Vue.set(state.images, image.url, image.payload)
}
},
actions: {
fetchImage ({state, commit}, url) {
if (state.images[url] !== undefined) {
return null
}
commit('setImage', {
url,
payload: null
})
return requests.get(url, { responseType: 'arraybuffer'}).then(response => {
commit('setImage', {
url,
payload: `data:${response.headers['content-type']};base64,${Buffer.from(response.data, 'binary').toString('base64')}`
})
})
}
}
}
언급URL : https://stackoverflow.com/questions/53171358/avoid-unnecessary-http-requests-on-identical-images-vuejs
'programing' 카테고리의 다른 글
vuex 파일을 분할하려면 어떻게 해야 합니까? (0) | 2022.08.14 |
---|---|
세미콜론 및 IF/WHILE/FOR 문이 없는 C의 hello world (0) | 2022.08.14 |
Vue.js 2 - 폼을 작은 컴포넌트로 분할하는 것은 나쁜 방법입니까? (0) | 2022.08.14 |
계산된 속성을 사용하여 구성 요소의 일부를 표시하거나 숨깁니다. (0) | 2022.08.14 |
페이지를 새로 고치면 성별 정보가 사라집니다. (0) | 2022.08.14 |