Using `this` to update useState in a function during build results in undefined error - Nuxt 3 & Strapi 4.12 - SFC (script setup)
P粉436410586
P粉436410586 2023-08-03 16:40:32
0
1
507
<p><br /></p><h2><br /></h2> <p><code>"@strapi/strapi": "4.12.0",</code></p> <p><code>"nuxt": "^3.6.5",</code></p> <p>In my development environment, I have a projects page with a category filter that shows either all projects or categories with corresponding projects. <br /><br />I am using useAsyncQuery to get items and categories from Strapi. <br /><br />In the filter, there is a drop-down menu with various categories. When these categories are clicked, the function switchCategory(filter.id) will be called. In this function, various states are updated using this.<br /><br />请查看以下脚本设置:</p><p><code></code></p> <pre class="brush:php;toolbar:false;"> import { projectsQuery } from "~/queries/projects/archive"; import { filterQuery } from "~/queries/projects/filter"; const { data: filterRes } = await useAsyncQuery(filterQuery) const { data: projectsRes } = await useAsyncQuery(projectsQuery) var isLoading = useState('isLoading', () => false) var filterActive = useState('filterActive', () => false) var filterActiveText = useState('filterActiveText', () => 'Alle projecten') const projectsUrl = useState('projectsUrl', () => '/projecten/') const filters = useState('filters', () => filterRes.value.projectCategories.data) const projects = useState('projects', () => projectsRes.value.projects.data) var filteredProjects = useState('filteredProjects', () => projects) function switchCategory(id) { this.isLoading = true this.filterActive = false; document.getElementById("projects-container").scrollIntoView({ behavior: 'smooth', }); setTimeout(() => { if (id) { this.filters.map((item) => { if (id == item.id) { this.filteredProjects = item.attributes.projects.data; this.filterActiveText = item.attributes.Title; } }); } else { this.filteredProjects = this.projects; this.filterActiveText = 'Alle projecten'; } this.isLoading = false; }, 600) }</pre> <p>并且在模板元素中:</p> <pre class="brush:php;toolbar:false;"><div class="flex flex-col gap-y-8 md:gap-y-24 lg:gap-y-40 transition-all duration-600 ease-in-out" :class="{ 'blur-0': !isLoading, 'blur': isLoading, }"> <div class="grid md:grid-cols-2 gap-8 md:gap-16 lg:gap-24 relative" v-for="(project, id) in filteredProjects" :key="id"> <Nuxt-Link class="absolute inset-0 w-full h-full z-10" :to="projectsUrl project.attributes.Slug"></Nuxt-Link> <div class="flex flex-col items-start justify-between"> <div class="sticky top-40 pb-16 lg:pb-20 prose-xl"> <h3 class="text-xl md:text-4xl lg:text-5xl font-bold">{{ project.attributes.Title }}</h3> <p class="block">{{ project.attributes.Intro }}</p> </div> <Button class="flex mb-4" color="light" :to="projectsUrl project.attributes.Slug"> Project bekijken </Button> </div> <div class="-order-1 md:order-1 relative"> <div class="aspect-video md:aspect-square lg:aspect-[12/18] relative"> <Media :url="project.attributes.FeaturedImage.data.attributes.url" :extension="project.attributes.FeaturedImage.data.attributes.ext" /> </div> </div> </div> </div></pre> <p>When I build the project, use nuxt build, and then use node .output/server/index.mjs to start a Node server, the project can load normally. But when I try to filter, while trying to update variables like isLoading and filterActive inside the switchCategory function, it throws the error: TypeError: Cannot set properties of undefined (setting 'isLoading'). <br /><br />Fix Attempt #1<br /><br />I thought, maybe after building, it doesn't understand this context (because when I try to console.log, this is also undefined). So I tried to refactor the code, like this: ; <pre class="brush:php;toolbar:false;">const switchCategory = (id) => { isLoading = true filterActive = false; document.getElementById("projects-container").scrollIntoView({ behavior: 'smooth', }); setTimeout(() => { if (id && filters) { filters && filters.value.map((item) => { if (id == item.id) { filteredProjects = item.attributes.projects.data; filterActiveText = item.attributes.Title; } }); } else { filteredProjects = projects; filterActiveText = 'Alle projecten'; } isLoading = false; }, 600) }</pre> <p>I changed the normal function to an arrow function and removed this. <br /><br />In setTimeout, I had to change filters.map to filters.value.map (not quite sure why the format changed). <br /><br />Now the code is running fine (no errors), but it is not updating the DOM of the item loop in the template. <br /><br />Fix Attempt #2<br /><br />After searching and debugging for quite some time, I found the content of defineExpose in the Vue documentation. <br /><br />It mentions that the script settings are "closed" by default. I (desperately) added this to my script settings, including all variables: </p><p><code></code><em></em></p> ; <pre class="brush:php;toolbar:false;">defineExpose({ filterRes, projectsRes, pageRes, isLoading, filterActive, filterActiveText, projectsUrl, filters, projects, filteredProjects, })</pre> <p>Unfortunately, as expected, it didn't magically work. <br /><br />Solution? <br />I'm probably looking at this the wrong way, but I can't think of any other solution.<br /><br />Am I missing something? </p><p><br /></p>
P粉436410586
P粉436410586

reply all(1)
P粉627427202

I'm not sure I can provide a complete working code snippet, but maybe I can guide you to a solution.

useState is only available when building or when the component is rendered. So changing the query parameters after rendering will not update it. Maybe re-rendering the component after a state change would help?


Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template