首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
vue.js
V2EX  ›  Vue.js

vue 的 computed 相关的一个问题,求助

  •  
  •   Hopetree · 94 天前 · 3005 次点击
    这是一个创建于 94 天前的主题,其中的信息可能已经有所发展或是发生改变。

    但愿这个图能显示

    情况如图所示,这个计算属性会在 sctext 变动时触发,实际上也的确会这样,但是我在 HTML 中使用{{ suggestion }}发现是空的,但是 console 日志会刷新值,所以很奇怪,为甚返回不到值?

    如果图挂了,看源码:

    <template>
        <div>
        	...	方便查看所以省略其他
            <p>{{ suggestion }}</p>
        </div>
    </template>
    
    <script>
    export default {
        data() {
            return {
                // 从 store 里面读取数据并使用
                sctype: "",
                scdata: {},
                sctypelist: [],
                sctext: "",
            };
        },
        created() {
            // 设置默认值
            var default_type = this.$store.getters.searchTypes[0];
            this.sctype = default_type;
            this.sctypelist = this.$store.getters.searchTypes;
            this.scdata = this.$store.state.searchList[default_type];
        },
        computed: {
            suggestion: function() {
                var a = ''
                this.$axios
                    .get("/baidu/su", { params: { wd: this.sctext } })
                    .then(ret => {
                        var json_str = ret.data.match(/s:(\[.*\])}\);/);
                        if (json_str) {
                            var json_str = json_str[1];
                        }
                        console.log(json_str);
                        a = json_str
                    });
                return a
            }
        },
        methods: {
            // 选择表单变化的时候同步数据
            changedata: function(command) {
                this.sctype = command;
                this.scdata = this.$store.state.searchList[command];
            }
        }
    };
    </script>
    
    <style scoped>
    img {
        width: 1.2rem;
        margin: 0rem 0.2rem -0.2rem 0rem;
    }
    </style>
    
    
    42 回复  |  直到 2019-09-03 17:05:36 +08:00
        1
    murmur   94 天前
    promise 是异步请求啊,你这个问题不懂的话建议先搞一下 promise 是个什么东西
    既然是异步 ajax 那返回也应该是一个 promise 才对
        2
    murmur   94 天前
    老老实实用 method 绑事件不好么 看你是搜索提示 这个建议直接用定时器检测改动 你不知道中文输入法有什么坑
    然后 a 做成 data 里的变量 检测到有文字输入就搜 搜了在 then 里赋值给 a suggestion 那里就是 a 了
        3
    xxx749   94 天前 via Android
    亲亲,这边建议您用 Watch 呢,您这边另起一个属性把 GET 拿到的数据赋值给这个属性就行了呢
        4
    krisfive   94 天前
    emmm 楼上 +1
        5
    hahasong   94 天前
    计算属性里套 ajax,令人窒息的操作。ajax 还没结束。空的 a 就被返回了
        6
    Allianzcortex   94 天前
    像是 async 和 await 的问题,因为 axios 返回的数据没有被用到,所以会 先 return 再 console.log(). 这里提一个 fix 的方法,把 return a 放到 resolvoe 函数里,楼主可以试下:

    var a = ' '

    a = this.$axios.get(...).then(... return json_str)
        7
    ochatokori   94 天前 via Android   ♥ 1
    建议先学习 js 异步的概念…

    这样说吧,你这个代码的执行顺序是
    var a='' //赋值,没问题
    axios //哦?这个是异步的,先发请求,结果丢一边等我有空再说
    return a//a 还空着,就被 computed 出去了
    //刚才有个异步还没处理,现在轮到你了
    //得到结果,给 a 赋值,这个时候 a 当然有值,但是 computed 方法早就跑完了
    //这里的流程实际上有问题,为了方便理解我省去了微任务和宏任务那些东西… promise 是微任务(面试要考)
        8
    Hopetree   94 天前
    @murmur
    @xxx749
    我现在是这样,的确能拿到返回值了,但是由于增加了一个属性,所以每次改动输入,都会重复调用 2 次接口,我还是看看你推荐的 watch 吧

    @hahasong 因为我是在学 vue,想着尽量用更多的插件来实现功能,都是为了探索
        9
    CDL   94 天前
    computed 只会监听 data,prop 这类属性值
        10
    Allianzcortex   94 天前
    @Allianzcortex 最后还要再 return a,其实是[因为要用到返回的结果]所以能保证[等到 axios 请求结果出来后再返回 computed 的结果]
        11
    Hopetree   94 天前
    @xxx749 非常感谢,我刚看了一下 watch,发现这个才是我需要的方法,已经实现了效果,下面是我改的

    ```
    watch: {
    sctext(val) {
    this.$axios
    .get("/baidu/su", { params: { wd: this.sctext } })
    .then(ret => {
    var json_str = ret.data.match(/s:(\[.*\])}\);/);
    if (json_str) {
    var json_str = json_str[1];
    }
    console.log(json_str);
    this.suggestion = json_str
    });
    }
    },
    ```
        12
    Allianzcortex   94 天前
    @ochatokori 我理解的流程也是这样的,那么这个 fix 方法理论上应该可以?
        13
    karnaugh   94 天前
    天秀。。。。
        14
    lqzhgood   94 天前 via Android
    用 watch 要 debounce
    不然你就是 ddos
        15
    Allianzcortex   94 天前
    @ochatokori 算了,看了下,除了 await 外确实没有别的方法,就算是用变量也不行
        16
    SilentDepth   94 天前
    @Allianzcortex #15 如果你是说要让这个过程「同步地」完成,强制循环等待法可解。只是,考虑到 JS 整体是单线程的,你的页面会被冻结(

    其实 computed 应对这种需求也不是没有用,只是直观上没那么方便。创建两个普通状态,loading 和 data,然后触发异步动作,首先 loading = true,异步返回后 loading = false 并把返回数据赋值给 data。计算属性同时访问这俩普通状态,当 loading === true 时返回占位内容,loading === false 时返回 data。因为 loading 的变化也会导致计算属性刷新,所以可以直接被模板使用。

    这些过程直接写到组件里会比较乱,所以用 Vue.obserable( ) 或 @vue/composition-api 是更好的做法。(是的我就是来安利 Vue 3 的~)
        17
    VancleefL   94 天前
    sctext 变动频繁吗?如果变动频繁记得加防抖..
        18
    Zink99   94 天前
    同步任务执行完成后才执行 .then() 中的代码,所以 a 是空

    了解下异步?
    https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/7
        19
    meepo3927   94 天前
    Ajax 异步 ,

    你 return a 的时候,a = json_str 还没有执行呢
        20
    no1xsyzy   94 天前
    @SilentDepth 阻塞式请求也是可以同步的,但也会冻结页面,不过 CPU 消耗比较少
        21
    tumobi   94 天前
    还是使用 async await 吧
        22
    no1xsyzy   94 天前
    基础概念问题…… 附一个 2014 年的演讲:
        23
    SilentDepth   94 天前
    @no1xsyzy #20 那个开关不是都被废弃了吗,没准哪天都不能用了(
        24
    hyy1995   94 天前
    你这个问题其实跟 vue 没啥关系,纯粹就是网络请求没请求完成前,你就 return 返回了,此时数据都还没取到,这就是个异步问题,太秀了吧。。。
        25
    liuguang   94 天前
    因为这个是异步的,请求还没完成,就 return 了
        26
    galikeoy   94 天前
    计算属性嵌套异步请求,龟龟,骚操作
        27
    jrtzxh020   94 天前 via iPhone
    有个 asyncComputed 的库 可以了解一下
        28
    lscho   94 天前
    亲亲,建议您学习一下 js 噢
        29
    mikoshu   94 天前
    只想说一句 666 好歹把 return 写到 promise 里面呀
        30
    Curtion   94 天前
    这是异步问题啊,和我初学 js 时犯的问题的一样,建议看看书巩固下基础
        31
    mikoshu   94 天前
    @mikoshu 就算 return 写到 promise 里 还得 return axios 然后返回一个 promise 估计也不好使 果然只能用 await 了 还有楼主改成 watch 的话 如果这个值变动很快 比如监听 input 的 input 事件 就得故意加延迟查询 不然请求太多
        32
    Biwood   94 天前 via Android
    1 楼和 7 楼都已经说到点子上了,去了解一下 JavaScript 同步和异步的原理和机制,比乱猜乱尝试有意义多了。后面还一堆扯到 async await 的,到底是有多菜啊各位,学习框架就真的不用学底层和基础知识了吗
        33
    tolking   94 天前
    建议你打开项目的 eslint 或者配置下。这种情况就会直接提示
    ```
    Unexpected asynchronous action in "suggestion" computed property.eslint(vue/no-async-in-computed-properties)
    ```
        34
    shintendo   94 天前
    上面说用 await 可以解决的各位,麻烦上个代码好吗?
        35
    shintendo   94 天前
    @Biwood +1 我都惊了
        36
    ljpCN   94 天前 via Android
    楼主已经解决了,而且也很耐心地去寻求解决方案并尝试。不过还是想说,学 vue 之前,先学 js
        37
    wunonglin   94 天前
    这边建议 lz 先重新学习 vue 呢亲,async 也要另外学一下
        38
    Sapp   94 天前
    我好久没用过 computed 了,但是我似乎记得,这个属性推荐的是做同步操作啊?你这个需求应该在坚挺某个输入的值变化,然后再调用请求,请求完成之后设置 this.a
        39
    mamahaha   94 天前
    你这个相当于是暗恋一个人,对方却不知道。
        40
    johnnyNg   94 天前
    建议重学 js
        41
    mikoshu   94 天前
    @Biwood
    @shintendo
    emmm 确实是 估计大家一开始都没想那么多 以为直接给 suggestion 加 async 然后在 promise 的位置 await 一下 再 return 就好了 (包括我也是,已经是习惯把 await 当成是同步了,是有点想当然了)因为毕竟是语法糖 这样会导致 computed 根本无法使用
        42
    supuwoerc   94 天前
    终于见到我会的问题了(滑稽)
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2409 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 25ms · UTC 14:13 · PVG 22:13 · LAX 06:13 · JFK 09:13
    ♥ Do have faith in what you're doing.