2017-03-08 3 views
2

Vue.js 계산 된 속성을 사용하고 있지만 문제가 있습니다. 계산 된 메서드 IS이 올바른 시간에 호출되었지만 계산 된 메서드에서 반환 된 값이 반환됩니다. 무시! console.log 문에 의해 인쇄Vue.js 계산 된 속성이 업데이트되지 않습니다.

내 방법

computed: { 
    filteredClasses() { 
     let classes = this.project.classes 
     const ret = classes && classes.map(klass => { 
      const klassRet = Object.assign({}, klass) 
      klassRet.methods = klass.methods.filter(meth => this.isFiltered(meth, klass)) 
      return klassRet 
     }) 
     console.log(JSON.stringify(ret)) 
     return ret 
    } 
} 

값이 올바른지,하지만 난 템플릿에 filteredClasses을 사용할 때, 그것은 단지 최초의 캐시 값을 사용하고 템플릿을 업데이트하지 않습니다. 이것은 Vue chrome devtools (filteredClasses 초기 캐싱 이후에 변경되지 않음)에 의해 확인됩니다.

아무도 나에게 왜 이런 일이 일어나고 있는지에 대한 정보를 줄 수 있습니까?

Project.vue는

<template> 
<div> 
    <div class="card light-blue white-text"> 
     <div class="card-content row"> 
      <div class="col s4 input-field-white inline"> 
       <input type="text" v-model="filter.name" id="filter-name"> 
       <label for="filter-name">Name</label> 
      </div> 
      <div class="col s2 input-field-white inline"> 
       <input type="text" v-model="filter.status" id="filter-status"> 
       <label for="filter-status">Status (PASS or FAIL)</label> 
      </div> 
      <div class="col s2 input-field-white inline"> 
       <input type="text" v-model="filter.apkVersion" id="filter-apkVersion"> 
       <label for="filter-apkVersion">APK Version</label> 
      </div> 
      <div class="col s4 input-field-white inline"> 
       <input type="text" v-model="filter.executionStatus" id="filter-executionStatus"> 
       <label for="filter-executionStatus">Execution Status (RUNNING, QUEUED, or IDLE)</label> 
      </div> 
     </div> 
    </div> 
    <div v-for="(klass, classIndex) in filteredClasses"> 
     <ClassView :klass-raw="klass"/> 
    </div> 
</div> 
</template> 

<script> 
import ClassView from "./ClassView.vue" 

export default { 
    name: "ProjectView", 

    props: { 
     projectId: { 
      type: String, 
      default() { 
       return this.$route.params.id 
      } 
     } 
    }, 

    data() { 
     return { 
      project: {}, 
      filter: { 
       name: "", 
       status: "", 
       apkVersion: "", 
       executionStatus: "" 
      } 
     } 
    }, 

    async created() { 
     // Get initial data 
     const res = await this.$lokka.query(`{ 
      project(id: "${this.projectId}") { 
       name 
       classes { 
        name 
        methods { 
         id 
         name 
         reports 
         executionStatus 
        } 
       } 
      } 
     }`) 

     // Augment this data with latestReport and expanded 
     const reportPromises = [] 
     const reportMeta  = [] 
     for(let i = 0; i < res.project.classes.length; ++i) { 
      const klass = res.project.classes[i]; 
      for(let j = 0; j < klass.methods.length; ++j) { 
       res.project.classes[i].methods[j].expanded = false 
       const meth = klass.methods[j] 
       if(meth.reports && meth.reports.length) { 
        reportPromises.push(
         this.$lokka.query(`{ 
          report(id: "${meth.reports[meth.reports.length-1]}") { 
           id 
           status 
           apkVersion 
           steps { 
            status platform message time 
           } 
          } 
         }`) 
         .then(res => res.report) 
        ) 
        reportMeta.push({ 
         classIndex: i, 
         methodIndex: j 
        }) 
       } 
      } 
     } 

     // Send all report requests in parallel 
     const reports = await Promise.all(reportPromises) 

     for(let i = 0; i < reports.length; ++i) { 
      const {classIndex, methodIndex} = reportMeta[i] 
      res.project.classes[classIndex] 
         .methods[methodIndex] 
         .latestReport = reports[i] 
     } 

     this.project = res.project 

     // Establish WebSocket connection and set up event handlers 
     this.registerExecutorSocket() 
    }, 

    computed: { 
     filteredClasses() { 
      let classes = this.project.classes 
      const ret = classes && classes.map(klass => { 
       const klassRet = Object.assign({}, klass) 
       klassRet.methods = klass.methods.filter(meth => this.isFiltered(meth, klass)) 
       return klassRet 
      }) 
      console.log(JSON.stringify(ret)) 
      return ret 
     } 
    }, 

    methods: { 
     isFiltered(method, klass) { 
      const nameFilter = this.testFilter(
       this.filter.name, 
       klass.name + "." + method.name 
      ) 
      const statusFilter = this.testFilter(
       this.filter.status, 
       method.latestReport && method.latestReport.status 
      ) 
      const apkVersionFilter = this.testFilter(
       this.filter.apkVersion, 
       method.latestReport && method.latestReport.apkVersion 
      ) 
      const executionStatusFilter = this.testFilter(
       this.filter.executionStatus, 
       method.executionStatus 
      ) 
      return nameFilter && statusFilter && apkVersionFilter && executionStatusFilter 
     }, 
     testFilter(filter, item) { 
      item = item || "" 
      let outerRet = !filter || 
      // Split on '&' operator 
      filter.toLowerCase().split("&").map(x => x.trim()).map(seg => 
       // Split on '|' operator 
       seg.split("|").map(x => x.trim()).map(segment => { 
        let quoted = false, postOp = x => x 
        // Check for negation 
        if(segment.indexOf("!") === 0) { 
         if(segment.length > 1) { 
          segment = segment.slice(1, segment.length) 
          postOp = x => !x 
         } 
        } 
        // Check for quoted 
        if(segment.indexOf("'") === 0 || segment.indexOf("\"") === 0) { 
         if(segment[segment.length-1] === segment[0]) { 
          segment = segment.slice(1, segment.length-1) 
          quoted = true 
         } 
        } 
        if(!quoted || segment !== "") { 
         //console.log(`Item: ${item}, Segment: ${segment}`) 
         //console.log(`Result: ${item.toLowerCase().includes(segment)}`) 
         //console.log(`Result': ${postOp(item.toLowerCase().includes(segment))}`) 
        } 
        let innerRet = quoted && segment === "" ? 
         postOp(!item) : 
         postOp(item.toLowerCase().includes(segment)) 

        //console.log(`InnerRet(${filter}, ${item}): ${innerRet}`) 

        return innerRet 
       }).reduce((x, y) => x || y, false) 
      ).reduce((x, y) => x && y, true) 

      //console.log(`OuterRet(${filter}, ${item}): ${outerRet}`) 
      return outerRet 
     }, 
     execute(methID, klassI, methI) { 
      this.project.classes[klassI].methods[methI].executionStatus = "QUEUED" 
      // Make HTTP request to execute method 
      this.$http.post("/api/Method/" + methID + "/Execute") 
      .then(response => { 
      }, error => 
       console.log("Couldn't execute Test: " + JSON.stringify(error)) 
      ) 
     }, 
     registerExecutorSocket() { 
      const socket = new WebSocket("ws://localhost:4567/api/Executor/") 

      socket.onmessage = msg => { 
       const {methodID, report, executionStatus} = JSON.parse(msg.data) 

       for(let i = 0; i < this.project.classes.length; ++i) { 
        const klass = this.project.classes[i] 
        for(let j = 0; j < klass.methods.length; ++j) { 
         const meth = klass.methods[j] 
         if(meth.id === methodID) { 
          if(report) 
           this.project.classes[i].methods[j].latestReport = report 
          if(executionStatus) 
           this.project.classes[i].methods[j].executionStatus = executionStatus 
          return 
         } 
        } 
       } 
      } 
     }, 
     prettyName: function(name) { 
      const split = name.split(".") 
      return split[split.length-1] 
     } 
    }, 

    components: { 
     "ClassView": ClassView 
    } 
} 
</script> 

<style scoped> 
</style> 
+0

명확히하기 위해,'filteredClasses' 메소드는'project.classes' 데이터가 변경 될 때마다 실행되지만 반환 값'ret'는 업데이트되지 않습니다? – Adam

+0

@Adam 로컬 변수'ret'가 올바르게 수정되고 있습니다. Vue는 그 값을 가져 가지 않고'vm.computed.filteredClasses'를 업데이트하지 않습니다 –

+0

'console.log (JSON.stringify (ret)) '가 올바른 값을 표시하지만'return ret'가 깨졌습니다. 다른 일이 일어나야 만합니다. 문제가 발생해야 할 이유가 없습니다. "'filteredClasses'는 초기 캐싱 후에 절대로 변경되지 않는다고 말할 때. 정확히 무슨 뜻이야? UI에서? 마지막으로 'filteredClasses'라고하는 메서드 나 데이터 속성이 없다는 것을 확신합니까? – Adam

답변

3

내가 전에 비슷한 문제로 실행하고 정기적 방법 대신 계산 된 속성을 사용하여 그것을 해결했습니다. 모든 것을 하나의 방법으로 옮기고 귀하의 입을 돌려 주십시오. Official docs.

+1

링크에는 comp. 속성 및 메서드. 메서드를 사용하면이 문제가 해결 될 수 있지만 메서드가 캐싱을 사용하지 않기 때문에 이상적인 솔루션은 아닙니다. –

+2

감사! 나는 또한 this. $ forceUpdate()를 사용했다. – Ehvince

0

v-for의 목록 항목에 고유 한 키 값을 할당해야합니다. 그렇게 ...

<ClassView :klass-raw="klass" :key="klass.id"/> 

그렇지 않으면, Vue는 어느 항목을 우연히 쓰는지 알지 못합니다. 설명 here https://vuejs.org/v2/guide/list.html#key

관련 문제