Vue 3의 합성 API를 사용하여 Vuex에서 자신을 해방

44555 단어 vuewebdevjavascript

Is there still room for Vuex with Vue 3?


Vue 3과 Composition API에 대한 이 시리즈를 끝내기 전에 마지막으로 제가 흥미롭게 생각하는 용례를 보여드리고 싶습니다.만약 당신이 아직 없다면, 한번 보세요. 그러면 당신은 문법에 대해 막연하지 않을 것입니다.
본고는 특히 Vuex를 배웠고 모든 데이터를 관리하는 곳에서 사용하는 경향이 있는 사람들을 대상으로 한다.
만약 당신이 이런 종류에 속하지 않거나 심지어 Vuex가 무엇인지 모른다면, 여기에 간단명료한 소개가 있습니다.

상점 하나가 그들 모두를 통치한다


문서에 따르면 Vuex는 "Vue.js 응용 프로그램의 상태 관리 모드 + 라이브러리"입니다.우리가 반응성과 합성 API를 가지기 전에 구성 요소 외부에 반응성 데이터를 저장하고 조작하는 곳으로 간주할 수 있다.
이 주제에 대한 Vue Mastery의 소개를 볼 수 없습니다.
위에서 말한 바와 같이, 이 라이브러리를 사용하면 구성 요소 트리에서 서로 멀리 떨어진 구성 요소가 공유하는 반응성 데이터를 외부화할 수 있습니다.
트리 아래에서 도구를 보내고 이벤트를 위로 보내는 대신 Vuex 저장소를 사용하여 통신할 수 있습니다.이렇게 하면 구성 요소 중 하나가 저장 상태를 수정할 때 구성 요소는 항상 최신입니다.
이 두 모델은 the library's home page 에서 나온다.먼저 두 개의 잎사귀 구성 요소가 통신할 수 있도록 관리해야 하는 복잡한 구성 요소 트리를 볼 수 있습니다.
Vue Mastery's introduction
여기서 Vuex 스토리지를 사용하여 통신을 단순화합니다.

Vuex 스토어는 다음 섹션으로 구성됩니다.

  • : 반응식 데이터가 있는 곳입니다.상태를 직접 수정할 수 없습니다.이 점을 하려면 돌변해야 한다.

  • state : 속성을 계산하는 것처럼 서로 다른 모양으로 상태를 표시하는 방법이다.그것들은 일반적으로 저장소의 모든 구성 요소 내부의 논리를 다시 쓰는 것을 피하는 데 쓰인다.

  • getters : 상태를 수정하는 유일한 방법은 돌연변이를 제출하는 것이다.그것들은 동기화되어야 하며, 가능한 한 작아야 한다.

  • mutations : 비동기 처리 또는 수정 상태의 많은 원소의 논리에 대해 우리는 조작을 스케줄링할 수 있다.

  • actions : 상태를 분할하기 위해 우리는 독립된 저장소, 즉 모듈을 만들 수 있다.
  • 상태는 한 무더기의 돌연변이를 나타냅니다. 이러한 돌연변이를 다시 보거나 깊이 있게 분석할 수 있습니다.
    modules
    이것은 단지 이론 소개일 뿐, 아직 시작하기에는 부족하다.통독하십시오.

    자세한 내용은 문서 참조 내 Vuex 문제


    Vuex는 모든 기술과 마찬가지로 비용이 있습니다.우선 도서관을 배우는 대가.내가 진행한 훈련에서, 나는 통상적으로 반나절의 시간을 써서 이 주제를 소개할 수 있다.야수를 길들이기 전에 너는 며칠의 연습을 더 할 수 있다.
    그 다음으로 Vuex를 사용할 때 데이터 책임의 개념을 잃는 경우가 많습니다.모든 사람이 상점의 상태를 수정할 수 있을 때, 데이터에 대한 책임은 구성 요소가 없다.이런 사고방식은 통상적으로 응용 프로그램을 유지하고 디버깅하기 어렵다. 등 위대한 도구를 사용할 때도 돌연변이가 누가 일어났는지, 왜 일어났는지 추적하기 어렵다.
    내가 "통상적"이라고 말할 때, 나는 고의로 개괄한 것이다.그것들은 Vuex의 실용적인 응용 프로그램으로 코드 라이브러리는 여전히 유지보수와 확장이 쉽다.그러나 내가 Vuex를 처음 배웠을 때 나는 그것을 과도하게 사용하는 경향이 있었다. 나는 내가 유일한 사람이 아니라고 생각했다.
    나의 관점은 Vuex를 거의 사용하지 않는다는 것이다. 특히 간단한 친자 소통 모델이 충분할 때이다.당신은 장시간의 디버깅과 두통을 피할 것입니다.
    그럼 어디서 사용할까요?어떤 용례는 매우 편리하다.아니면 내가 "어디에서 쓸모가 있었는지"라고 말해야 하는데, 지금 우리는 합성 API가 생겼다.예시 프로그램으로 사용자 정보를 표시하고 편집한 예시를 설명해 보겠습니다.

    Vue 개발 도구 Vuex를 사용하여 사용자 데이터 관리


    본고는 Vuex 설치를 소개하지 않을 것입니다. 필요하면 를 따르십시오.
    우선 우리가 무엇을 건설할지 봅시다.우리는 결코 완전한 웹 응용 프로그램을 만드는 것이 아니다. 이것은 본문의 범위를 넘어선다.그러나 만약 당신이 아직 만나지 않았다면, 우리는 당신이 만날 수 있는 흔한 부분을 구축할 것입니다.이 두 섹션은 다음과 같습니다.
  • Header 구성 요소로 사용자 닉네임과 개인 자료 사진을 표시합니다.
  • 데이터 편집 가능 UserSettings 구성 요소.
  • 여기서 Vuex를 사용하는 것은 좀 지나치다.응용 프로그램의 나머지 부분은 무시되었습니다. 복잡한 구성 요소 트리와 Vue 공유기를 설치했습니다.
    실제 API 호출은 api.js 파일에서 외부화됩니다.Promisefetch처럼 하나만 되돌려줄 수 있다.
    상점의 사용자 모듈부터 실시합니다.
    import { loadUserInfo, saveNewUserInfo } from './api';
    
    const AVAILABLE_STATUS = {
        LOADING: 'LOADING',
        UPDATING: 'UPDATING',
        ERROR: 'ERROR',
    };
    
    export const user = {
        namespaced: true,
        state() {
            return {
                nickname: '',
                pictureUrl: '',
                status: '',
            };
        },
        getters: {
            isLoading: state => state.status === AVAILABLE_STATUS.LOADING,
            isUpdating: state => state.status === AVAILABLE_STATUS.UPDATING,
            errorOccurred: state => state.status === AVAILABLE_STATUS.ERROR,
        },
        mutations: {
            changeStatus(state, newStatus) {
                state.status = newStatus;
            },
            changeNickname(state, newNickname) {
                state.nickname = newNickname;
            },
            changePicture(state, newPicture) {
                state.pictureUrl = newPicture;
            },
        },
        actions: {
            // Called by the "App" component to ensure that the initial data are loaded
            load({ commit }) {
                commit('changeStatus', AVAILABLE_STATUS.LOADING);
                loadUserInfo()
                    .then(({ nickname, pictureUrl }) => {
                        commit('changeNickname', nickname)
                        commit('changePicture', pictureUrl)
                        commit('changeStatus', '');
                    })
                    .catch(() => {
                        commit('changeStatus', AVAILABLE_STATUS.ERROR);
                    })
            },
            update({ commit }, newUser) {
                commit('changeStatus', AVAILABLE_STATUS.UPDATING);
                saveNewUserInfo(newUser)
                    .then(({ nickname, pictureUrl }) => {
                        commit('changeNickname', nickname)
                        commit('changePicture', pictureUrl)
                        commit('changeStatus', '');
                    })
                    .catch(() => {
                        commit('changeStatus', AVAILABLE_STATUS.ERROR);
                    })
            },
        },
    };
    
    여기서 우리는 두 가지 중요한 일이 있다.우선, 닉네임과 그림의 URL을 사용하여 소비하는 상태입니다.axios 작업으로 인해 구성 파일도 수정할 수 있습니다.
    또한 스토어에서 로드 상태를 관리하여 구성 요소가 사용자에게 적절한 메시지를 표시할 수 있도록 합니다.
    제목 구성 요소는 현재 저장된 데이터를 사용할 수 있습니다.
    <template>
        <header>
            <template v-if="isLoading">
                User information are loading
            </template>
            <template v-else-if="isUpdating">
                User information are updating
            </template>
            <template v-else-if="errorOccurred">
                Unable to manage user information
            </template>
            <template v-else>
                Welcome {{ nickname }}
                <img :src="pictureUrl" alt="User picture" class="user-picture">
            </template>
        </header>
    </template>
    
    <script>
    import { mapState, mapGetters } from 'vuex';
    
    export default {
        name: 'app-header',
        computed: {
            ...mapState({
                nickname: state => state.user.nickname,
                pictureUrl: state => state.user.pictureUrl,
            }),
            ...mapGetters({
                isLoading: 'user/isLoading',
                isUpdating: 'user/isUpdating',
                errorOccurred: 'user/errorOccurred',
            }),
        },
    }
    </script>
    
    <style >
    .user-picture {
        height: 40px;
        width: 40px;
        border-radius: 50%;
    }
    </style>
    
    마지막으로 update 구성 요소는 같은 작업을 수행하고 사용자가 수정을 검증할 때 사용합니다.
    <template>
        <form @submit.prevent="updateUser">
            <label>
                Nickname
                <input type="text" v-model="newNickname">
            </label>
            <label>
                Picture url
                <input type="text" v-model="newPicture">
            </label>
            <input type="submit" value="Validate changes" :disabled="formDisabled">
            <p v-if="errorOccurred">An error has occurred while managing user information...</p>
        </form>
    </template>
    
    <script>
    import { mapState, mapGetters } from 'vuex';
    
    export default {
        name: 'user-settings',
        data() {
            return {
                newNickname: '',
                newPicture: '',
            };
        },
        computed: {
            ...mapState({
                nickname: state => state.user.nickname,
                pictureUrl: state => state.user.pictureUrl,
            }),
            ...mapGetters({
                isLoading: 'user/isLoading',
                isUpdating: 'user/isUpdating',
                errorOccurred: 'user/errorOccurred',
            }),
            formDisabled() {
                return this.isLoading || this.isUpdating
            },
        },
        watch: {
            nickname: {
                handler() {
                    this.newNickname = this.nickname;
                },
                immediate: true,
            },
            pictureUrl: {
                handler() {
                    this.newPicture = this.pictureUrl;
                },
                immediate: true,
            },
        },
        methods: {
            updateUser() {
                if (!this.formDisabled) {
                    this.$store.dispatch('user/update', {
                        nickname: this.newNickname,
                        pictureUrl: this.newPicture,
                    })
                }
            },
        },
    };
    </script>
    
    이 해결 방안은 실행할 수 있다고 말할 수 있다. 그가 옳다.그러나 나는 몇 가지 결점을 보았다.
  • 우리는 구성 요소가 초기 데이터 불러오는 것을 책임지도록 해야 한다.
  • 간단해 보이는 임무는 완전하고 복잡한 라이브러리가 필요하다.
  • 작성된 API를 사용하면 결과가 더 좋습니까?어디 보자!

    파일 작성된 API 결과와 동일합니까?


    이 응용 프로그램을 합성 API로 재구성하는 데 시간이 오래 걸리지 않아야 합니다.
    우선, 우리는 우리의 상점을 대체하기 위해 ES 모듈을 만들 것이다.우리는 어떻게 모든 소비자 간에 데이터를 공유하는 모듈을 만듭니까?우리는 단례 설계 모델을 사용할 수 있다.
    import { ref, computed } from "vue";
    
    import { loadUserInfo, saveNewUserInfo } from './api';
    
    const AVAILABLE_STATUS = {
        LOADING: 'LOADING',
        UPDATING: 'UPDATING',
        ERROR: 'ERROR',
    };
    
    // These data will only be created once and thus be shared by the consumers
    const nickname = ref('');
    const pictureUrl = ref('');
    const status = ref('');
    
    // Computed properties based on the status
    const isLoading = computed(() => status.value === AVAILABLE_STATUS.LOADING);
    const isUpdating = computed(() => status.value === AVAILABLE_STATUS.UPDATING);
    const errorOccurred = computed(() => status.value === AVAILABLE_STATUS.ERROR);
    
    // No need for mutations anymore, we can simply create JS methods
    const apiCallReturnedWithNewUserInformation = ({ nickname: loadedNickname, pictureUrl: loadedPictureUrl }) => {
        nickname.value = loadedNickname;
        pictureUrl.value = loadedPictureUrl;
        status.value = '';
    }
    const load = () => {
        status.value = AVAILABLE_STATUS.LOADING;
        loadUserInfo()
            .then(apiCallReturnedWithNewUserInformation)
            .catch(() => {
                status.value = AVAILABLE_STATUS.ERROR;
            });
    };
    
    const update = (newUser) => {
        status.value = AVAILABLE_STATUS.UPDATING;
        saveNewUserInfo(newUser)
            .then(apiCallReturnedWithNewUserInformation)
            .catch(() => {
                status.value = AVAILABLE_STATUS.ERROR;
            })
    };
    
    // Fetch the user info when the module will be used for the first time
    load();
    
    // Export a method that returns every needed piece of information
    export const useUserManager = () => ({
        load,
        update,
        nickname,
        pictureUrl,
        status,
        isLoading,
        isUpdating,
        errorOccurred,
    });
    
    다음은 구성 요소에서 데이터를 사용하는 방식을 바꿔야 합니다.
    <template>
        <header>
            <template v-if="isLoading">
                User information are loading
            </template>
            <template v-else-if="isUpdating">
                User information are updating
            </template>
            <template v-else-if="errorOccurred">
                Unable to manage user information
            </template>
            <template v-else>
                Welcome {{ nickname }}
                <img :src="pictureUrl" alt="User picture" class="user-picture">
            </template>
        </header>
    </template>
    
    <script>
    import { useUserManager } from './user/userManager';
    
    export default {
        name: 'app-header',
        setup() {
            const userManager = useUserManager();
            return {
                pictureUrl: userManager.pictureUrl,
                nickname: userManager.nickname,
                isLoading: userManager.isLoading,
                isUpdating: userManager.isUpdating,
                errorOccurred: userManager.errorOccurred,
            }
        },
    }
    </script>
    
    <style >
    .user-picture {
        height: 40px;
        width: 40px;
        border-radius: 50%;
    }
    </style>
    
    <template>
        <form @submit.prevent="updateUser">
            <label>
                Nickname
                <input type="text" v-model="newNickname">
            </label>
            <label>
                Picture url
                <input type="text" v-model="newPicture">
            </label>
            <input type="submit" value="Validate changes" :disabled="formDisabled">
            <p v-if="errorOccurred">An error has occurred while managing user information...</p>
        </form>
    </template>
    
    <script>
    import { ref, computed, watchEffect } from 'vue';
    import { useUserManager } from './userManager';
    export default {
        name: 'user-settings',
        setup() {
            const newNickname = ref('');
            const newPicture = ref('');
    
            const userManager = useUserManager();
            const formDisabled = computed(() => {
                return userManager.isLoading.value || userManager.isUpdating.value;
            });
    
            watchEffect(() => newNickname.value = userManager.nickname.value);
            watchEffect(() => newPicture.value = userManager.pictureUrl.value);
    
            const updateUser = () => {
                if (!formDisabled.value) {
                    userManager.update({
                        nickname: newNickname.value,
                        pictureUrl: newPicture.value,
                    });
                }
            }
    
            return {
                newNickname,
                newPicture,
                pictureUrl: userManager.pictureUrl,
                nickname: userManager.nickname,
                isLoading: userManager.isLoading,
                isUpdating: userManager.isUpdating,
                errorOccurred: userManager.errorOccurred,
                formDisabled,
                updateUser,
            }
        },
    };
    </script>
    
    마지막으로, 상점의 파일을 삭제하고 응용 프로그램에서 의존 항목을 삭제할 수 있습니다!
    엔드 유저에게는 동일한 결과가 제공되지만 애플리케이션은 Vue 이외의 라이브러리에 의존하지 않습니다.
    그러나 나는 이것이 결코 묘약이 아니라고 말할 수 밖에 없었다.만약 당신이 모든 물건을 하나의 큰 모듈에 넣는다면, 응용 프로그램은 여전히 디버깅과 유지보수가 매우 어렵다.API를 작성하는 것은 도구이고 훌륭한 도구이지만 그뿐입니다.만약 실지로 사용하지 않는다면, 그것은 이익보다 폐단이 클 것이다.
    우리가 지은 것은 사실상 간단한 것으로 간주될 수 있다.우리는 합성 API가 제공하는 선명성과 모듈성을 이용하여 개발자와 사용자의 우호적인 상태 관리 모델을 만들었다.

    어떤 일들은 끝났어요...


    당신은 이런 상태 관리 모델이 어떻다고 생각합니까?당신은 당신의 신청에서 그것을 사용할 것을 고려할 수 있습니까?
    이것은 내가 처음으로 이렇게 많은 주제에 관한 문장을 쓴 것이다.나는 네가 나처럼 많은 것을 배울 수 있기를 바란다.
    저에게 이 시리즈와 당신에 관한 경험을 피드백해 주십시오. 저는 당신들 모두를 매우 기쁘게 읽을 것입니다!

    좋은 웹페이지 즐겨찾기