Vue: [๊ธฐ๋Šฅ] Vue ๊ด€์ฐฐ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ธฐ๋Šฅ

์— ๋งŒ๋“  2016๋…„ 04์›” 07์ผ  ยท  50์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: vuejs/vue

์—…๋ฐ์ดํŠธ:
๋ˆ„๊ตฐ๊ฐ€ ์ด ๊ธฐ๋Šฅ์„ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฒฝ์šฐ ์ ์ ˆํ•œ ๊ถŒ๊ณ ์™€ ๋ชจ๋“  ๊ฒƒ์„ ํฌํ•จํ•˜์—ฌ vue-nonreactive ๋กœ ์ถœ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.


Vue์˜ ๊ด€์ฐฐ ๋ฐ ๊ฑท๊ธฐ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•˜๋Š” ๋น„์ผ๋ฐ˜ ๋ชจ๋ธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋Š” ๊ด€๋ จ ์ž์›์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋„๋ก ์บ์‹œ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋Š” ์ž์› ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์บ์‹œ์˜ ๋ชจ๋“  ๊ฐœ์ฒด๊ฐ€ ๊ฐ์‹œ๋˜๊ณ (์•„๋งˆ๋„ ๋น„ํšจ์œจ์ ์ž„) ๋‹ค๋ฅธ ์ฝ”๋“œ์™€์˜ ์ถ”๊ฐ€ ์ƒํ˜ธ ์ž‘์šฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์บ์‹œ์— ๋”๋ฏธ ๊ด€์ฐฐ์ž๋ฅผ ์„ค์ •ํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋ญ”๊ฐ€ ๋น„์Šทํ•œ...

import get from 'http';
import Resource from 'resource';


new Vue({
    data: { instance: {}, },
    ready() { this.fetch(); },

    methods: {
        fetch() {
            const Observer = Object.getPrototypeOf(this.instance.__ob__).constructor;

            get('/api/frobs')
            .then(function(data) {
                // initialize Resource w/ JSON document
                const resource = new Resource(data);

                // Protect cache with dummy observer
                resource.cache.__ob__ = new Observer({});

                this.instance = resource;
            });
        },
    },
});

์ด๊ฒƒ์€ ์ž‘๋™ํ•˜์ง€๋งŒ

  • vue์˜ ๋‚ด๋ถ€์— ์˜์กด
  • Observer ํด๋ž˜์Šค๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ด๋ฏธ ๊ด€์ฐฐ๋œ ๊ฐœ์ฒด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ œ์•ˆ:
Vue์˜ ๊ด€์ฐฐ/๋ณดํ–‰์„ ๋ช…์‹œ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ณต์‹ ๋ฐฉ๋ฒ•์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€...

const someThing = {
  nestedThing: {},
};

// make entire object non-reactive
Vue.nonreactive(someThing);

// make nested object non-reactive
Vue.nonreactive(someThing.nestedThing);
vm.$set('key.path', someThing);

๊ณ ๋ ค ์‚ฌํ•ญ:

  • ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ˜์‘ํ•˜์ง€ ์•Š๋Š” ๊ฐœ์ฒด์— ๋ฐ˜์‘ ํ‚ค ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ฉ๋‹ˆ๊นŒ? vue๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฒฝ๊ณ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด,

``` js
vm.$set('a', Vue.nonreactive({});

//์™€ ๋‹ค๋ฅด๋‹ค..
vm.$set('์•„', {
someKey: Vue.nonreactive({}),
});
```

  • ๋น„๋ฐ˜์‘ํ˜•์œผ๋กœ ๋งŒ๋“ค๋ ค๊ณ  ํ•˜๋ฉด ์ด๋ฏธ ๋ฐ˜์‘์ ์ธ ๊ฐœ์ฒด๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฒฝ๊ณ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด,

``` js
// ์˜ค๋ฅ˜
Vue.nonreactive(vm.$data.a)

// ์œ ํšจํ•œ
Vue.nonreactive(_.clone(vm.$data.a));
```

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

  1. data ์˜ ๊ฐ์ฒด/๋ฐฐ์—ด์— ๋Œ€ํ•œ ๊ด€์ฐฐ์„ ๊ฑด๋„ˆ๋›ฐ์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ Object.freeze() ๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.
  2. ๋‹น์‹ ์€์—์„œ ๊ฐœ์ฒด๋ฅผ ๋„ฃ์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค data ์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•ด this . created() hook์˜ this ์— ๊ฐ„๋‹จํžˆ ๋ถ™์ด๋ฉด ์ „ํ˜€ ๊ด€์ฐฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  50 ๋Œ“๊ธ€

๊ท€ํ•˜์˜ ๊ฒฝ์šฐ์—๋Š” Object.freeze() ๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? v1.0.18๋ถ€ํ„ฐ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

  1. data ์˜ ๊ฐ์ฒด/๋ฐฐ์—ด์— ๋Œ€ํ•œ ๊ด€์ฐฐ์„ ๊ฑด๋„ˆ๋›ฐ์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ Object.freeze() ๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.
  2. ๋‹น์‹ ์€์—์„œ ๊ฐœ์ฒด๋ฅผ ๋„ฃ์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค data ์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•ด this . created() hook์˜ this ์— ๊ฐ„๋‹จํžˆ ๋ถ™์ด๋ฉด ์ „ํ˜€ ๊ด€์ฐฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • Object.freeze ๋Š” ์—ฌ๊ธฐ์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์บ์‹œ๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค.
  • ์ฃผ์š” ์ž์›์€ _is_ ๋ฐ˜์‘์ ์ž…๋‹ˆ๋‹ค. ์ €๋Š” ์ฃผ๋กœ ์ค‘์ฒฉ๋œ ์บ์‹œ ๊ฐœ์ฒด๋ฅผ ๋น„๋ฐ˜์‘ํ˜•์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ชจ๋ธ ๋””์ž์ธ์„ ์žฌ๊ณ ํ•ด์•ผ ํ•  ๋•Œ์ž…๋‹ˆ๋‹ค. ์™œ ๊ทธ๋Ÿฐ ๊ฒƒ๋“ค์„ ๊ด€์ฐฐํ•  ๋Œ€์ƒ ์•„๋ž˜์— ๋‚ดํฌํ•ฉ๋‹ˆ๊นŒ?

์บ์‹œ๋Š” ๊ด€๋ จ ๋ฆฌ์†Œ์Šค๋ฅผ ๋™์ ์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด Author ๋ฐ Post ๋ชจ๋ธ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž‘์„ฑ์ž ๋ชจ๋ธ์€ ๊ฒŒ์‹œ๋ฌผ ๋ชจ๋ธ์— ๋Œ€ํ•ด posts ๋ผ๋Š” ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ์บ์‹œ์—๋Š” ๊ด€๊ณ„ ๋ฐ์ดํ„ฐ์™€ ๊ด€๋ จ ์ปฌ๋ ‰์…˜์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

author.posts๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์บ์‹œ์—์„œ ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

์˜๋„์ ์œผ๋กœ Vue๋Š” ์ž์ฒด ์ƒํƒœ ๋ณ€๊ฒฝ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์žˆ๋Š” ๋ณต์žกํ•œ ๊ฐ์ฒด๋ฅผ Vue ์ธ์Šคํ„ด์Šค์˜ data ๋„ฃ๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Vue ์ธ์Šคํ„ด์Šค์— ๊ด€์ฐฐ๋œ ๋ฐ์ดํ„ฐ๋กœ ์ˆœ์ˆ˜ ์ƒํƒœ ๋งŒ ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ƒํƒœ๋Š” ์›ํ•˜๋Š” ๋Œ€๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋Ÿฌํ•œ ์กฐ์ž‘์„ ๋‹ด๋‹นํ•˜๋Š” ๊ฐ์ฒด๋Š” Vue ์ธ์Šคํ„ด์Šค ์ƒํƒœ์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฒซ์งธ, ๋ช…ํ™•ํ•œ ์งˆ๋ฌธ - ์ˆœ์ˆ˜ ์ƒํƒœ ๋ž€ ์ •ํ™•ํžˆ ๋ฌด์—‡์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ์ƒํƒœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ชจ๋ธ ์ƒํƒœ(์˜๊ตฌ์ , ์ €์žฅ์†Œ์™€ ๋™๊ธฐํ™”๋œ ๋ฐ์ดํ„ฐ, ์˜ˆ: todo)
  • vue ์ƒํƒœ(์ž„์‹œ, ๋ณด๊ธฐ ๋™์ž‘์„ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๋ฐ์ดํ„ฐ. ์˜ˆ: ํ•  ์ผ ๋ชฉ๋ก ์ถ•์†Œ/ํ‘œ์‹œ)

ํ•˜์ง€๋งŒ ์–ด์จŒ๋“ :
๊ณต์ • ํ•ด. ๋ชจ๋ธ์€ ํ™•์‹คํžˆ '๋ณต์žก'ํ•˜๋ฏ€๋กœ ์ด ์š”์ฒญ์€ ํ˜„์žฌ ๋ชจ๋ฒ” ์‚ฌ๋ก€์— ์œ„๋ฐฐ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๋‚ด ์ดˆ๊ธฐ ์˜ˆ๋Š” ๊ทธ๋‹ค์ง€ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ด€์ฐฐ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ฐ ํšจ๊ณผ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ฐ€๋Šฅํ•œ ์‚ฌ์šฉ๋ฒ•์ด ์žˆ๋Š” ํ˜„์žฌ ์„ค์ •์„ ๋” ์ž˜ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

<!-- layout -->
<post :post="post"></post>
<author :author="author" ><author>
<comments :comments="comments"></comments>
import post from 'components/post';
import author from 'components/author';
import comments from 'components/comments';
/* post = {
 *     template: '...'
 *     props: ['post'],
 *     data: () => {collapsed: false},
 *     ...
 * };  */

new Vue({
    el: 'body',
    data() { 
        instance = postStore.fetch({include: ['author', 'comments.author']})
        Vue.nonreactive(instance.cache)

        return {post: instance, },
    },
    components: {
        post,
        author,
        comments,
    },
    ...
});

๊ธฐ๋ณธ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ ˆ์ด์•„์›ƒ์— ๋ฐฐ์น˜ํ•˜๊ณ  ๊ด€๋ จ ๊ตฌ์„ฑ ์š”์†Œ์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๋ถ€๋ชจ ๋ทฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ์ปจํ…์ŠคํŠธ๋งˆ๋‹ค ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ž์‹ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ž์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, _user์˜_ ๋Œ“๊ธ€ ๋ชฉ๋ก๊ณผ _post์˜_ ๋Œ“๊ธ€ ๋ชฉ๋ก.

๋ชจ๋ธ์€ ๊ด€๋ จ ๊ฐœ์ฒด๊ฐ€ ์ค‘์ฒฉ๋˜์ง€ ์•Š๊ณ ( {post: {author: {}, comments: []}} ) ๋Œ€์‹  ์บ์‹œ์—์„œ ์กฐํšŒ๋œ๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๊ณ ๋Š” ์ƒ๋‹นํžˆ '๋ฉ์ฒญํ•œ' ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, post.comments[2].author ๋Š” post.author ์™€ ๋™์ผํ•œ ๊ฐ์ฒด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ž‘์„ฑ์ž ๊ฐœ์ฒด์˜ ๋ณต์‚ฌ๋ณธ์ด ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ๋Š” ๋Œ€์‹  ์บ์‹œ์—์„œ ์กฐํšŒ๋œ ๋ณต์‚ฌ๋ณธ ํ•˜๋‚˜๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ๋‚ด์šฉ์—๋Š” ๋ณ€ํ˜•์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋Š” ์ดˆ๊ธฐ ๊ฐ€์ ธ์˜ค๊ธฐ์—์„œ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

๋˜ํ•œ ์š”์ฒญ์ด ๋” ์ด์ƒ ๊ด€๋ จ์ด ์—†๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๋Œ€์•ˆ์€ '๋น„๊ณต๊ฐœ' ๊ฐœ์ฒด ๊ตฌ์„ฑ์›์„ ๊ด€์ฐฐํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์„ ํ–‰ ๋‹จ์ผ ๋˜๋Š” ์ด์ค‘ ๋ฐ‘์ค„์ด ์žˆ๋Š” ๊ตฌ์„ฑ์›์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋‹จ์ ์€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊นจ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€ ์ด ๊ธฐ๋Šฅ์„ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฒฝ์šฐ ์ ์ ˆํ•œ ๊ถŒ๊ณ ์™€ ๋ชจ๋“  ๊ฒƒ์„ ํฌํ•จํ•˜์—ฌ vue-nonreactive ๋กœ ์ถœ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

@rpkilby ๊ณต์œ 

@rpkilby ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌํ•˜๊ณ  ๊ด€์ฐฐ ๊ฐ€๋Šฅ/๋ฐ˜์‘์„ฑ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

var newObj = JSON.parse(JSON.stringify(obj))

"์ƒํƒœ" ๋ฐฐ์—ด์„ ์œ ์ง€ํ•˜๊ณ  vuex์—์„œ ์ƒํƒœ ๊ธฐ๋ก ๊ฐ์ฒด๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ง ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํŽธ์ง‘ : ์ด ์†”๋ฃจ์…˜์€ ์ œ ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํŠน์ • ์‹œ์ ์— ์†์„ฑ ๊ฐ’์˜ ๋ณต์‚ฌ๋ณธ๋งŒ ํ•„์š”ํ•œ ๊ฐœ์ฒด๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ฐธ์กฐ, ๋™์  ์—…๋ฐ์ดํŠธ ๋“ฑ์€ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ ๋‹น์žฅ ๊ฐœ์ฒด๋ฅผ ๋™๊ฒฐํ•˜๋Š” ๊ฒƒ์€ ์žฅ๊ธฐ์ ์ธ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹™๋‹ˆ๋‹ค. [Vue-nonreactive]๋Š” Vue๋ฅผ ์ข…์†์„ฑ์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ, ์ด๋Š” ๊ณง์žฅ ์•ž์œผ๋กœ ๋‚˜์•„๊ฐ€๋Š” ์ผ์— ๊ด€ํ•ด์„œ๋Š” ๊ณผ๋„ํ•ฉ๋‹ˆ๋‹ค. instance.__ob__ !== false ์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ ํ™•์ธ์œผ๋กœ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„๊นŒ์š”? ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์บ์‹œ์™€ ๊ฐ™์€ ํ•ญ๋ชฉ์ด ๊ด€์ฐฐ๋˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Unobservable {
  construtor() {
    Object.defineProperty(this, '__ob__', {  
      enumerable: false,  configurable: false,
      writable: false, value: false,
    });
  }
}

์ด๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„ Vue ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค(์ ์–ด๋„ ์ €์—๊ฒŒ๋Š”).

Vue์— 1๋ ˆ๋ฒจ ๋ฐ์ดํ„ฐ ๊นŠ์ด๋งŒ ๊ฐ์‹œ(defineProperty to)ํ•˜๋„๋ก ์ง€์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ œ ๊ฒฝ์šฐ๋Š” data.curObj ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ Vue๊ฐ€ ์•Œ๋ฆผ์„ ๋ฐ›๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ curObj.position , curObj.rotation ๋“ฑ์€ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

Object.freeze ๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ์ด ๊ฒฝ์šฐ three.js๊ฐ€ ๊ฐœ์ฒด์— ๊ฐ’์„ ํ• ๋‹นํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜๋ฅผ ํ•ด์•ผ ํ•˜๋‚˜์š”?
(์‹ค์€ ๋น„์Šทํ•œ ๊ณณ์—์„œ ํ–ˆ์–ด์š”)

data () {
  return {
    wrapper: Object.freeze({
      actual: [bigData]
    })
  }
},
methods: {
  operation () {
    this.wrapper = Object.freeze({
      actual: [newBigData]
    })
  }
}

// core/observer/watch.js
function _traverse (val: any, seen: ISet) {
  let i, keys
  const isA = Array.isArray(val)
  if ((!isA && !isObject(val)) || !Object.isExtensible(val)) {
    return
  }
  // ...
// core/observer/index.js
export function observe (value: any, asRootData: ?boolean): Observer | void {
  if (!isObject(value) || value instanceof VNode) {
    return
  }
  let ob: Observer | void
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else if (
    observerState.shouldConvert &&
    !isServerRendering() &&
    (Array.isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value._isVue
  ) {
    ob = new Observer(value)
  }
  // ...
> curObj PerspectiveCamera {uuid: "BD3C14DF-8C2B-4B96-9900-B3DD0EAC1163", name: "PerspectiveCamera", type: "PerspectiveCamera", parent: null, children: Array(0),ย โ€ฆ}

> Lodash.isPlainObject(curObj) false
> Vue.isPlainObject(curObj) true
  1. Object.isExtensible ( Object.freeze ) ์™ธ์— ์‚ฌ์šฉ์ž๊ฐ€ ๊ด€์ฐฐ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๋‹ค๋ฅธ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
  2. Vue.isPlainObject ๊ฐ์ง€๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ตฌ์กฐํ™”๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var newObj = { ...obj };

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. isPlainObject ๋ฉ”์„œ๋“œ๊ฐ€ false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

/**
 * Makes an object and it's children unobservable by frameworks like Vuejs
 */
class Unobservable {
  /**
   * Overrides the `Object.prototype.toString.call(obj)` result
   * <strong i="6">@returns</strong> {string} - type name
   * <strong i="7">@see</strong> {<strong i="8">@link</strong> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag}
   */
  get [Symbol.toStringTag]() {
    // Anything can go here really as long as it's not 'Object'
    return 'ObjectNoObserve';
  }
}
>> Object.prototype.toString.call(new Unobservable());
   "[object ObjectNoObserve]"

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„, ์‘๋‹ต์—์„œ ์žƒ์–ด๋ฒ„๋ฆฐ ํ•œ ๊ฐ€์ง€ ํฌ์ธํŠธ๋Š” ์›๋ž˜ ์ฃผ์„์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ˆœ์ˆ˜ํ•œ ์ƒํƒœ ๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” ๊ด€๊ณ„ ์กฐํšŒ ์บ์‹œ์— ๋Œ€ํ•œ ๊ฐœ์ธ ์ฐธ์กฐ๊ฐ€ ์žˆ๋Š” ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด article ๋Š” author ๋˜๋Š” comments ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. article.author ํ˜ธ์ถœํ•˜๋ฉด ์ด๋Š” ํ•ด๋‹น ๊ด€๊ณ„ ์บ์‹œ์— ๋Œ€ํ•œ ๋™์  ์†์„ฑ ์กฐํšŒ์ด๋ฉฐ ๋‹จ์ˆœํ•œ ์†์„ฑ ์•ก์„ธ์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ณ ๋ คํ•ด์•ผ ํ•  ๋ช‡ ๊ฐ€์ง€ ์‚ฌํ•ญ:

  • ์บ์‹œ๋Š” ์ˆœ์ˆ˜ํ•œ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„์ด๋ฏ€๋กœ Vue์—์„œ ์บ์‹œ๋ฅผ ๊ด€์ฐฐํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ ๋™์  ์กฐํšŒ/์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ์—ฌ์ „ํžˆ ์ฐธ์กฐ๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ ์บ์‹œ๋ฅผ ๋ฒ„๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ์บ์‹œ๋Š” ์‚ฌ์‹ค์ƒ ์‹ฑ๊ธ€ํ†ค์ด๋ฉฐ ์™ธ๋ถ€์—์„œ ์—…๋ฐ์ดํŠธ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ์— ๋”ฐ๋ผ ์•ฑ์ด ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค.

๋ช‡ ๊ฐ€์ง€ ์ œ์•ˆ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ:

  • JSON stringify/parse ๋˜๋Š” object destructuring์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐœ์ฒด ๋ฐ ์บ์‹œ๊ฐ€ ๋ณต์ œ๋˜๊ณ  ์›๋ณธ ์บ์‹œ์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ์†์ƒ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์›๋ž˜ ์บ์‹œ ์ฐธ์กฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด๋„ ๋” ์ด์ƒ ์•ฑ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋™์  ์กฐํšŒ ๋ฐ ์—…๋ฐ์ดํŠธ๊ฐ€ ์—†์œผ๋ฉด ์บ์‹œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฌด์˜๋ฏธํ•˜๋ฉฐ ๊ด€๋ จ ๊ฐœ์ฒด๋ฅผ ์›๋ž˜ ๋ชจ๋ธ์˜ ๊ฐ„๋‹จํ•œ ์†์„ฑ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ๊ฒƒ์€ ์ด๋Ÿฌํ•œ ์ œ์•ˆ์ด ์ด๋Ÿฌํ•œ ๊ฐœ์ฒด์˜ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๋ฅผ ์†์ƒ์‹œํ‚จ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • @Mechazawa ์˜ ์ œ์•ˆ์€ ์œ ํ˜• ์ƒ์„ฑ์„ ์ œ์–ดํ•˜๊ณ  ์œ ํ˜•์ด Vue์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋„๋ก ๋นŒ๋“œ๋œ ๊ฒฝ์šฐ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” Vue์— ์–ฝ๋งค์ด์ง€ ์•Š์€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์œ ํ˜•์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์„ ๊ฒช๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. vue ๋ ˆ์ด์–ด๊ฐ€ ํŠน์ • ์•Œ๋ ค์ง„ ์†์„ฑ์„ ๊ด€์ฐฐํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์œผ๋กœ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

๋‚˜์˜ ์œ ์ผํ•œ ๋น„ํŒ:

Vue-nonreactive๋Š” Vue๋ฅผ ์ข…์†์„ฑ์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ์ด๋Š” ์ง์ ‘์ ์ธ ์ผ์„ ํ•  ๋•Œ ์ง€๋‚˜์น˜๊ฒŒ ๋งŽ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์™œ ๋‚˜์œ ์ผ์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ด๋ฏธ Vue๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ Vue์—๋งŒ ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ‹€๋ฆฌ์ง€ ์•Š์•˜๋‹ค๋ฉด ๋Œ€๋ถ€๋ถ„์˜ ๋นŒ๋“œ ๋„๊ตฌ๋Š” ์ค‘๋ณต ์ข…์†์„ฑ์ด ์žˆ๋Š” ๋ฒˆ๋“ค์„ ๋งŒ๋“ค์ง€ ์•Š์„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ๋˜‘๋˜‘ํ•ฉ๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ์ด๊ฒƒ์€ ์˜ณ์ง€ ์•Š์Šต๋‹ˆ๋‹ค . ๊ฐœ๋ฐœ ์ข…์†์„ฑ์€ ์žˆ์ง€๋งŒ ๋Ÿฐํƒ€์ž„ ์ข…์†์„ฑ์€ ์—†์Šต๋‹ˆ๋‹ค.


์–ด์จŒ๋“ , ์ด ๊ฒŒ์‹œ๋ฌผ์ด ์•ฝ๊ฐ„์˜ ๊ด€์‹ฌ์„ ์–ป์€ ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜ ์ค‘ ์ผ๋ถ€๋Š” ๋‹ค๋ฅธ ๋‹ค์–‘ํ•œ ๊ฒฝ์šฐ์— ์ž‘๋™ํ•  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹จ์ˆœํžˆ ๋‚ด ์›๋ž˜ ์˜๊ฒฌ์˜ ์š”๊ตฌ ์‚ฌํ•ญ๊ณผ ์ œ์•ˆ ์‚ฌํ•ญ์ด ๊ทธ ๊ฒฝ์šฐ์— ์ ํ•ฉํ•œ ๋Œ€์•ˆ์ด ์•„๋‹Œ ์ด์œ ๋ฅผ ๊ฐ•์กฐํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ตœ๊ทผ์— ์ด ๋ฌธ์ œ๋ฅผ ์ ‘ํ–ˆ๊ณ  Vue์˜ ๊ด€์ฐฐ ๋…ผ๋ฆฌ๋ฅผ ๋‹จ๋ฝ์‹œํ‚ค๋Š” ํ›จ์”ฌ ์‰ฌ์šด ๋ฐฉ๋ฒ•์ด ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. _๊ตฌ์„ฑํ•  ์ˆ˜ ์—†๋Š” ์†์„ฑ์œผ๋กœ ์ •์˜._

๋ฐฐ๊ฒฝ

๋‚ด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์œ ํ•˜๊ณ  ๋ฐ˜์‘์„ฑ ์‹œ์Šคํ…œ์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(OpenLayers)์™€ ํ•จ๊ป˜ ์ž‘์—…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜๋ฅผ ๊ตฌ๋ถ€๋ฆฌ๋ ค๊ณ ํ•˜๋ฉด ๋„ˆ๋ฌด ๋งŽ์€ ๋‘ํ†ต์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ ์œ ์ผํ•œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์€ OpenLayers๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ  ์ œ๊ฐ€ Vue๊ฐ€ ์ด๋Ÿฌํ•œ ๋”์ฐํ•˜๊ฒŒ ์ค‘์ฒฉ๋œ uber ๊ฐ์ฒด๋กœ ๋” ๋ฉ‹์ง€๊ฒŒ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ์ฐพ๊ธฐ ์ „์— ๋‚ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์•ฝ 3๊ธฐ๊ฐ€์˜ ๋žจ(๊ฐ€์žฅ ํฐ ๋ฐ์ดํ„ฐ ์„ธํŠธ์—์„œ)์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ, ์ด ๋ชจ๋“  ๊ฒƒ์ด Vue๊ฐ€ ์ด๋Ÿฌํ•œ ๊ฐœ์ฒด๋ฅผ ๋ฐ˜์‘ํ˜•์œผ๋กœ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋กœ๋”ฉํ•  ๋•Œ ์†๋„๊ฐ€ ์ •๋ง ๋Š๋ ธ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” Vue-nonreactive๋ฅผ ์‹œ๋„ํ–ˆ๊ณ  ๋„์›€์ด ๋˜์—ˆ์ง€๋งŒ ์šฐ๋ฆฌ๋ฅผ ์•ฝ 1๊ธฐ๊ฐ€๋กœ ์ค„์˜€์Šต๋‹ˆ๋‹ค. Vue๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์—๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด 350๋ฉ”๊ฐ€ ์ •๋„์˜€์Šต๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ์ฑ…

๋ฐ˜์‘ํ•˜์ง€ ์•Š์œผ๋ ค๋Š” ๊ฒƒ์€ configurable: false ๋กœ ํ‘œ์‹œํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

Object.defineProperty(target, 'nested', { configurable: false });

(์ด๋ ‡๊ฒŒ ํ•˜๋ฉด nested ์†์„ฑ์ด ์ค‘์ง€๋˜๊ณ  ๋ชจ๋“  ์†์„ฑ์ด ๊ด€์ฐฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)

๊ทธ๊ฒŒ ๋‹ค์•ผ! Vue ์ข…์†์„ฑ์ด ์—†์œผ๋ฉฐ ํ‹€๋ฆผ์—†์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋‚ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๊ฐ€์žฅ ํฐ ๋ฐ์ดํ„ฐ ์„ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ 200๋ฉ”๊ฐ€๋กœ ์ค„์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ณ  ์‰ฌ์šฐ๋ฉฐ Vue ์ธก์—์„œ ๋ฌธ์„œ ๋ณ€๊ฒฝ๋งŒ ํ•˜๋ฉด ๋ฐ˜์‘์ด ์—†๋Š” '๊ณต์‹' ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค - ํ™•์‹คํžˆ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๋Œ€์•ˆ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

๊ด€์ฐฐ ๋ฐ˜์‘์„ ์ผ์‹œ์ ์œผ๋กœ ์ผ์‹œ ์ค‘์ง€ํ•˜๊ณ  ๋‚˜์ค‘์— ์ผ์‹œ ์ค‘์ง€๋ฅผ ํ•ด์ œํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚˜๋Š” ์†Œํ’ˆ ๊ฐ์‹œ์ž๊ฐ€ ์žˆ๋Š”๋ฐ, ๊ทธ ์•ˆ์—์„œ ์ „์ฒด ๋ฐ์ดํ„ฐ ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋œ ํ›„์—๋งŒ DOM ์—…๋ฐ์ดํŠธ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๊ณ  ์‹ถ์ง€ ์•Š์€ ๊ฑฐ๋Œ€ํ•œ ๊ฐœ์ฒด๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

@intijk ์ •ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋ฌด์—‡์„ ํ•˜๋ ค๋Š”์ง€์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. Vue๋Š” ๊ฒฐ๊ตญ ์ƒํƒœ๋ฅผ ์ ์šฉํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๊ณ„์‚ฐํ•˜๋Š” ๋™์•ˆ ๋‹จ์ˆœํžˆ ์ผ์‹œ ์ค‘์ง€ํ•˜๋Š” ๊ฒƒ์€ ๋ณ„๋กœ ๋„์›€์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  ์ตœ์ข… ์ƒํƒœ๋งŒ ์ ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ƒˆ ๊ฐœ์ฒด๋กœ ์‹œ์ž‘ํ•œ ๋‹ค์Œ ๋งˆ์ง€๋ง‰์— ํ•ด๋‹น ๊ฐœ์ฒด๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด(์˜์‚ฌ ์ฝ”๋“œ):

doUpdate()
{
   const state = _.cloneDeep(this.myState);

  // Do intermediate state updates

  this.myState = state;
}

(๊ฐ์ฒด ๋ฐ˜์‘์„ฑ์— ๋Œ€ํ•œ ์ผ๋ฐ˜ Vue ์ฃผ์˜ ์‚ฌํ•ญ์ด ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.)

๋‚ด ์ถ”์ฒœ์€ ์œ„์˜ configurable ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ˜์‘ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ํฐ ๊ฐœ์ฒด์˜ ์„น์…˜์„ ๊ฑด๋„ˆ๋›ฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์ด ๋ฐ˜์‘ํ•ด์•ผ _ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ vuex ์™€ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

@Morgul ์ด๋ฏธ ์˜ค๋žซ๋™์•ˆ ์ด ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ์‚ฌ์‹ค์€ ๋” ์ด์ƒ ์ด ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ œ ๊ฒฝ์šฐ์—๋Š” ๋ฐ์ดํ„ฐ ๊ฐœ์ฒด๊ฐ€ 2M์—์„œ 100M ์‚ฌ์ด์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ์ด๋Ÿฌํ•œ ๊ฐœ์ฒด์— ๋Œ€ํ•ด ๊นŠ์€ ๋ณต์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ณ ํ†ต์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

@intijk Vue๋ฅผ ๋ฐ”์ธ๋”ฉํ•  ๋ฌด์–ธ๊ฐ€์— ๋Œ€ํ•ด ์—„์ฒญ๋‚˜๊ฒŒ ๋ณต์žกํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@๋ชจ๊ตด
์ผ€์ด์Šค๊ฐ€ ๋ณต์žกํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š๊ณ  ์ผ€์ด์Šค ์ž์ฒด๊ฐ€ ๋‹จ์ˆœํ•˜๊ณ  ๋ฐ์ดํ„ฐ๊ฐ€ ํฝ๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ๊ฐ€ ์ธ๋ฑ์‹ฑ๋œ ์‹œ๊ฐํ™” ๋กœ๊ทธ ํŒŒ์ผ์„ ๋กœ๋“œํ•  ๋•Œ๋งˆ๋‹ค ์ด๋ฅผ ํ‘œ์‹œํ•  ์‹œ๊ฐํ™” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์‚ฐ๋œ ์†์„ฑ ๋‚ด์—์„œ ๋น„๋ฐ˜์‘์„ฑ ํ•„๋“œ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚ด ์ฒซ ๋ฒˆ์งธ ์•„์ด๋””์–ด๋Š” ๋ฐฐ์—ด์— ๋Œ€ํ•œ ํ• ๋‹น์˜ ๋น„ ๋ฐ˜์‘์„ฑ์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค ...

template: '<div v-html="markdown.render(input, env)"></div>',
props: ['id', 'input'],
computed: {
  env:      function() { return { reactive:this.id, non_reactive:[] } },
  markdown: function() { return Markdown },
},

// within markdown.render():
  env.non_reactive[0] = internal_data;

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์ •ํ™•ํžˆ ์ž์ฒด ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค :-)

์–˜๋“ค ์•„. ๋ฐฉ๊ธˆ ์ด ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๊ณ  rpkilby์˜ ๋ฌธ์ œ์™€ ๋งค์šฐ ์œ ์‚ฌํ•œ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ณ  ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ํ”„๋กœ์ ํŠธ๋Š” JSON ๊ฐœ์ฒด์—์„œ ์ผ๋ จ์˜ Vue ๊ฐ€์ƒ DOM(๋˜๋Š” vnode๋ผ๊ณ  ํ•จ)์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด JSON ๊ฐœ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Android ์•ฑ์„ ๊ตฌ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ์ด JSON ๊ฐ์ฒด๋Š” ํฌ๊ธฐ๊ฐ€ ์ปค์„œ Vue์—์„œ ์ด JSON์„ ์‚ฌ์šฉํ•˜๋ฉด Vue์—์„œ ๊ด€์ฐฐ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” rpkilby์™€ Morgul์˜ ๋ฐฉ์‹์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (BTW ์ €๋Š” ํŒ€์— ์†ํ•ด ์žˆ์ง€๋งŒ ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์€ Vue์— ์ต์ˆ™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์•„๋งˆ๋„ JSON์ด ๊ด€์ฐฐ๋˜๊ณ  Vue ๋ฒ„์ „์€ 2.5.16์ž…๋‹ˆ๋‹ค. ). Vue ํŠธ๋ž˜๋ฒ„์Šค์—์„œ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.
๊ธฐ๋Šฅ _traverse (๋ฐœ, ๋ณธ) {
var i, ํ‚ค;
var isA = Array.isArray(๋ฐœ);
if ((!isA && !isObject(val)) || Object.isFrozen(val) || VNode์˜ val instance
|| (๋ฐœ && ๋ฐœ['__vueNonReactive__'])) {
๋ฐ˜ํ’ˆ
}
...
๋ณด์‹œ๋‹ค์‹œํ”ผ "val && val['__vueNonReactive__']"๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ JSON์˜ ๋ฃจํŠธ ๋…ธ๋“œ๋กœ "__vueNonReactive__ = true"๊ฐ€ ๋˜๋„๋ก JSON ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์ด ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ์ฒด์˜ ์†์„ฑ์„ ๊ตฌ์„ฑํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ Vue์—์„œ ๊ด€์ฐฐํ•˜๋„๋ก ๊ตฌ์„ฑํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” Vue์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๊นŒ?(Object.freeze๋Š” ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๊ฐ์ฒด๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ชจ๋“  ์ƒํ™ฉ์— ๋งž์ถœ ์ˆ˜ ์—†์Œ)

์ด๊ฒƒ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
set val._isVue = true ๋Š” vue ๊ด€์ฐฐ ์ ˆ์ฐจ์—์„œ ๋ฒ—์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜ ์ €๋Š” Vue๊ฐ€ mapbox-gl์˜ ๋งต ์ธ์Šคํ„ด์Šค๋ฅผ ๊ด€์ฐฐํ•œ ํ›„ ์ด์ƒํ•œ ์ผ์ด ๋ฐœ์ƒํ•˜์—ฌ ๋งต์ด ๊ฐ€๋ฒผ์›Œ์ง€๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งŒ๋‚ฌ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งต ์ธ์Šคํ„ด์Šค๋Š” vue ์ธ์Šคํ„ด์Šค ๊ฐ„์— ์ „๋‹ฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. map._isVue = true ์ถ”๊ฐ€ํ•œ ํ›„ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

+1 ๊ณต์‹์ ์œผ๋กœ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๋ฐ˜์‘์„ฑ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ํฐ ๊ฐœ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ฐ˜์‘์„ฑ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๊ฐœ์ฒด ํฌ๊ธฐ๊ฐ€ 800MB์—์„œ 43MB๋กœ ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.
ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ๋กœ @magicdawn ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€๋งŒ @Mechazawa ๊ฐ€ ์—ฌ๊ธฐ์—์„œ ๊ฐ€์žฅ ์ข‹์€ ์†”๋ฃจ์…˜์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
__ob__ ์˜ configurable ๋ฅผ false ๋กœ ์„ค์ •ํ•˜๋Š” ์†”๋ฃจ์…˜์˜ ๊ฒฝ์šฐ ์‹ค์ œ __ob__ ๋ฅผ ์„ค์ •ํ•˜๋ ค๊ณ  ํ•  ๋•Œ Vue๊ฐ€ ์ถฉ๋Œํ•ฉ๋‹ˆ๋‹ค.

Vue ๋ณ€์ˆ˜๋ฅผ ๋น„๋ฐ˜์‘ํ˜•์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” Vue ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋นŒ๋“œํ–ˆ์Šต๋‹ˆ๋‹ค(beforeCreate ํ›„ํฌ ์‚ฌ์šฉ).

์ด๊ฒƒ์€ vue-nonreactive - @rpkilby ๋ณด๋‹ค ๊นจ๋—ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ฃผ์„์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. ๊ท€ํ•˜์˜ ์†”๋ฃจ์…˜์€ Vue์˜ ๋‹ค์Œ ๋ฒ„์ „์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


๋ณ€์ˆ˜๋ฅผ ๋น„๋ฐ˜์‘ํ˜•์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ Vue-Static ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

<script>
export default {
    static() {
        return {
            map: null,
        };
    },
    mounted() {
        this.map = new mapboxgl.Map({...}); /* something heavy */
    },
};
</script>

์•ˆ๋…•ํ•˜์„ธ์š” @samuelantonioli - vue-static์ด ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ์ „์ฒด ๊ฐœ์ฒด์— ๋Œ€ํ•œ ๋ฐ˜์‘์„ฑ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋Œ€์กฐ์ ์œผ๋กœ, vue-nonreactive๋Š” ๋‹จ์ผ ์†์„ฑ์— ๋Œ€ํ•œ ๊ด€์ฐฐ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋ฉด์„œ ๋‚˜๋จธ์ง€ ๊ฐ์ฒด๋Š” ๋ฐ˜์‘ ์ƒํƒœ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ์˜๋„๊ฐ€ ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ •์  ์†์„ฑ์€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ด€์ฐฐํ•˜์ง€ ์•Š์ง€๋งŒ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋น„๋ฐ˜์‘์„ฑ ์†์„ฑ์€ ๊ด€์ฐฐํ•˜๊ฑฐ๋‚˜ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‚ด ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค์—๋Š” ๊ด€๋ จ ๊ฐœ์ฒด ์กฐํšŒ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ๊ฐœ์ฒด ์บ์‹œ์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. instance ๋ฐ ๊ด€๋ จ instance.author ์„ ๊ด€์ฐฐ/๋ Œ๋”๋งํ•˜๊ณ  ์‹ถ์ง€๋งŒ instance._cache ๋Š” ์•„๋‹™๋‹ˆ๋‹ค.

new Vue({
    data() {
        const instance = postStore.fetch({include: ['author', 'comments.author']})
        Vue.nonreactive(instance._cache)

        return {post: instance, },
    },
    ...
});

์–ด๋Š ์ชฝ์ด๋“ , ๋จธ๋ฆฌ๋ฅผ ๋“ค์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ฒ„์ „์—์„œ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ณ  ๊ด€์ฐฐ์ž/ํ”„๋ก์‹œ ์ƒ์„ฑ์„ ์†์ผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@LinusBorg - ์‹คํ—˜ ๋ถ„๊ธฐ๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ฒ„์ „์˜ ๊ฐœ๋ฐœ์€ ์–ด๋””์—์„œ ์ง„ํ–‰๋˜๋‚˜์š”?

์šฐ๋ฆฌ๋Š” ์•„์ง ๊ฐœ๋…/์‹คํ—˜ ๋‹จ๊ณ„์ด๊ณ  ์•„์ง ๋ถ„๊ธฐ๋ฅผ ๊ฒŒ์‹œํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์— ๋Œ€ํ•œ ์ง„์ง€ํ•œ ์ž‘์—…์€ 2.6 ์—…๋ฐ์ดํŠธ๊ฐ€ ์ถœ์‹œ๋˜๊ธฐ ์ „์—๋Š” ์‹œ์ž‘๋˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. vue-cli 3.0์ด ๊ณง ์ถœ์‹œ๋˜๊ธฐ๋ฅผ ํฌ๋งํ•˜๋Š” ํ›„์— ์ž์ฒด์ ์œผ๋กœ ์•ฝ๊ฐ„์˜ ์ž‘์—…์ด ํ•„์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ES6 ํ”„๋ก์‹œ๊ฐ€ ๋„์ž…๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋™์ผํ•œ ๋ฒ”์œ„์— ์žˆ๋Š”์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚ด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋‚˜๋Š” ๊ทธ๊ฒƒ๋“ค์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋ฉฐ vue์˜ ํ˜„์žฌ ๊ด€์ฐฐ์— ๋Œ€ํ•œ ์˜ค๋ฒ„ ํ—ค๋“œ ๋Œ€ ์˜ค๋ฒ„ ํ—ค๋“œ๊ฐ€ ํ›จ์”ฌ ์ž‘์•„ ๋ณด์ž…๋‹ˆ๋‹ค. ์•…๋งˆ๋Š” ์„ธ๋ถ€ ์‚ฌํ•ญ์—์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Vue-Static ์— ๋Œ€ํ•œ ๋ฌธ์ œ๋Š” ์ค‘๋ณต๋˜๋Š” ๋Š๋‚Œ์ด ๋“ ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” JS ๋ชจ๋“ˆ์—์„œ ๋‚ด ๊ฐ์ฒด๋ฅผ ๋นŒ๋“œํ•˜๊ณ  ๊ทธ๋ฅผ ๊ฐ€์ ธ์˜จ ๋‹ค์Œ ๊ณ„์‚ฐ๋œ ํ•จ์ˆ˜์—์„œ ๊ทธ์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€์ฐฐ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ณ„์‚ฐ๋œ ํ•จ์ˆ˜์˜ ๊ฐ’์ด ๋‹ค์‹œ ๊ณ„์‚ฐ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚ด vue ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋…ผ๋ฆฌ ์œ ํ˜• ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ›จ์”ฌ ๋” ๋‚˜์€ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ์ž…๋‹ˆ๋‹ค.

์–ด์จŒ๋“  ์†์„ฑ์„ ๊ตฌ์„ฑ ๋ถˆ๊ฐ€๋Šฅ์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๋‚ด ํŠธ๋ฆญ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋ฌธ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ๊ฐ€์žฅ ๋œ ์นจ์Šต์ ์ด๊ณ  Vue์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ES ํ”„๋ก์‹œ์™€ ์ค‘๋‹จ๋  ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•  ์ด์œ ๋„ ์—†์Šต๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ๊ตฌ์„ฑํ•  ์ˆ˜ ์—†๋Š” ์†์„ฑ์„ ๊ด€์ฐฐํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์™„์ „ํžˆ ํ‹€๋ฆด ์ˆ˜๋Š” ์žˆ์ง€๋งŒ __ob__ ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค๋Š” ๊ฒƒ์„ _์•Œ๊ณ _... ์šฐ๋ฆฌ๋Š” ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ์†์„ฑ์— ๋Œ€ํ•œ ๊ฒ€์‚ฌ์— ๋Œ€ํ•ด ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ 8๊ฐœ์›” ์ด์ƒ ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ์—์„œ ์ฑ”ํ”ผ์–ธ์ฒ˜๋Ÿผ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. ;) (@samuelantonioli์™€ ๋น„์Šทํ•œ ๋ฌธ์ œ ๊ณต๊ฐ„์ด ์žˆ์Šต๋‹ˆ๋‹ค. Vue๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ 2.4๊ธฐ๊ฐ€๋กœ ํ™•์žฅํ•˜์ง€ ์•Š๊ณ ๋„ Vue ๋‚ด๋ถ€์—์„œ ์ž‘์—…ํ•ด์•ผ ํ•˜๋Š” OpenLayers ๋งต์ด ์žˆ์Šต๋‹ˆ๋‹ค...)

๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์˜ค๊ณ  ๊ณ„์‚ฐ๋œ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ Vue-Static์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ง์›๋“ค์ด ์ดํ•ดํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๊ฐ€๋ฅด์น  ์ˆ˜ ์žˆ๋Š” ํŒจํ„ด์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. import-module-and-use-computed-properties ํŒจํ„ด์€ ๊ทธ๋ ‡๊ฒŒ ๋ช…ํ™•ํ•œ IMO๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.


์•ฝ๊ฐ„ OT: ES6 ํ”„๋ก์‹œ๊ฐ€ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ํ™•์‹ ํ•˜์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜์„ฑ์— ๋Œ€ํ•ด ๋ช‡ ๊ฐ€์ง€ ์šฐ๋ ค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(IE11 ์ดํ•˜์—์„œ๋Š” ์ง€์›ํ•˜์ง€ ์•Š์Œ). ๋ธŒ๋ผ์šฐ์ € ์š”๊ตฌ ์‚ฌํ•ญ์ด ๋” ์—„๊ฒฉํ•œ ํ”„๋กœ์ ํŠธ์— Vue๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ˜ธํ™˜์„ฑ ๋ ˆ์ด์–ด/์ผ๋ถ€ ์œ ํ˜•์˜ ํด๋ฆฌํ•„์ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Vue์— 1๋ ˆ๋ฒจ ๋ฐ์ดํ„ฐ ๊นŠ์ด๋งŒ ๊ฐ์‹œ(defineProperty to)ํ•˜๋„๋ก ์ง€์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ด ์•„์ด๋””์–ด์— ๋Œ€ํ•ด +1, Vue๋ฅผ ์™ธ๋ถ€ Graphic lib(์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์ค‘ ์ˆ˜์ค€์˜ ์ค‘์ฒฉ๋œ ํฐ ๊ฐœ์ฒด๊ฐ€ ์žˆ์Œ)์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์กฐํ™”ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ผ๋ถ€ ์†์„ฑ๋งŒ ๋ฐ˜์‘ํ˜•์œผ๋กœ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

์—ฌ๊ธฐ์— ๋ถ„๋ช…ํ•œ ๊ฒƒ์„ ๋†“์ณค์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ this.propertyName = { /* ์—ฌ๊ธฐ์— ํฐ ๊ฒƒ์„ ์‚ฌ์šฉ */ };
Mounted() ํ›„ํฌ์—์„œ ๊ด€์ฐฐ๋˜์ง€ ์•Š๋Š” ์†์„ฑ์„ ๊ฐ–๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด ์•„๋‹™๋‹ˆ๊นŒ?

์•ˆ๋…•ํ•˜์„ธ์š” @vlahanas์ž…๋‹ˆ๋‹ค. https://github.com/vuejs/vue/issues/2637#issuecomment -403630456์„ ์ฐธ์กฐ

_isVue ๋ฅผ ์„ค์ •ํ•˜๋ฉด vue-devtool์ด ์ถฉ๋Œํ•˜๋ฏ€๋กœ ์ด ๊ธฐ๋Šฅ์„ ๋Œ€์‹  ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

export default function setIsVue(val) {
    if (!val) return

    Object.defineProperty(val, '_isVue', {
        value: true,
        enumerable: false,
        configurable: true,
    })

    // vue-devtool
    // https://github.com/vuejs/vue-devtools/blob/c309065c57f6579b778341ea37042fdf51a9fc6c/src/backend/index.js#L616
    // ๅ› ไธบๆœ‰ _isVue ๅฑžๆ€ง
    if (process.env.NODE_ENV !== 'production') {
        if (!val.$options) {
            Object.defineProperty(val, '$options', {
                value: {},
                enumerable: false,
                configurable: true,
            })
        }

        if (!val._data) {
            Object.defineProperty(val, '_data', {
                value: {},
                enumerable: false,
                configurable: true,
            })
        }
    }

    return val
}

๊ทธ๊ฒƒ์€ ์†Œ์Œ ์†์—์„œ ๊ธธ์„ ์žƒ์—ˆ์ง€๋งŒ ์†์„ฑ์„ ๊ตฌ์„ฑ ๋ถˆ๊ฐ€๋Šฅ์œผ๋กœ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์€ ์‹ค์ œ๋กœ ์ˆ˜์ •์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

Object.keys(scene).forEach((key)=>{
  Object.defineProperty(target, 'nested', { configurable: false });
});

THREE.Scene ๋ฅผ ์ „๋‹ฌํ•  ํ•„์š”๊ฐ€ ์žˆ์ง€๋งŒ ๋ฌธ์ž ๊ทธ๋Œ€๋กœ ์ „์ฒด ์žฅ๋ฉด ๊ทธ๋ž˜ํ”„๊ฐ€ ๊ด€์ฐฐ ๊ฐ€๋Šฅ ํ•ญ๋ชฉ์˜ ์—‰๋ง์ด ๋˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š์„ ๋•Œ ์ •๋ง ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์›๋ณธ ๊ฐœ์ฒด๋ฅผ ๊ณ„์† ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์™„๋ฒฝํ•œ!

์—ฌ์ „ํžˆ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.
๋น„๋ฐ˜์‘ํ˜•์œผ๋กœ ์œ ์ง€ํ•˜๋ ค๋Š” ์†์„ฑ์˜ ์ค‘์ฒฉ๋œ ์ˆ˜์ค€์ด ๋งŽ์ด ํฌํ•จ๋œ ๊ฐœ์ฒด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
1

๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋”๋ผ๋„

๊ทธ๊ฒƒ์€ ์†Œ์Œ ์†์—์„œ ๊ธธ์„ ์žƒ์—ˆ์ง€๋งŒ ์†์„ฑ์„ ๊ตฌ์„ฑ ๋ถˆ๊ฐ€๋Šฅ์œผ๋กœ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์€ ์‹ค์ œ๋กœ ์ˆ˜์ •์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

Object.keys(scene).forEach((key)=>{
  Object.defineProperty(target, 'nested', { configurable: false });
});

THREE.Scene ๋ฅผ ์ „๋‹ฌํ•  ํ•„์š”๊ฐ€ ์žˆ์ง€๋งŒ ๋ฌธ์ž ๊ทธ๋Œ€๋กœ ์ „์ฒด ์žฅ๋ฉด ๊ทธ๋ž˜ํ”„๊ฐ€ ๊ด€์ฐฐ ๊ฐ€๋Šฅ ํ•ญ๋ชฉ์˜ ์—‰๋ง์ด ๋˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š์„ ๋•Œ ์ •๋ง ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์›๋ณธ ๊ฐœ์ฒด๋ฅผ ๊ณ„์† ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์™„๋ฒฝํ•œ!

๋˜๋Š”

์ด๊ฒƒ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
set val._isVue = true ๋Š” vue ๊ด€์ฐฐ ์ ˆ์ฐจ์—์„œ ๋ฒ—์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜ ์ €๋Š” Vue๊ฐ€ mapbox-gl์˜ ๋งต ์ธ์Šคํ„ด์Šค๋ฅผ ๊ด€์ฐฐํ•œ ํ›„ ์ด์ƒํ•œ ์ผ์ด ๋ฐœ์ƒํ•˜์—ฌ ๋งต์ด ๊ฐ€๋ฒผ์›Œ์ง€๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งŒ๋‚ฌ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งต ์ธ์Šคํ„ด์Šค๋Š” vue ์ธ์Šคํ„ด์Šค ๊ฐ„์— ์ „๋‹ฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. map._isVue = true ์ถ”๊ฐ€ํ•œ ํ›„ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ค‘์ฒฉ๋œ ๊ฐ์ฒด์˜ ์†์„ฑ์€ ๋ฐ˜์‘ํ˜•์ด ๋ฉ๋‹ˆ๋‹ค.

์žฌ๊ท€ ์ ์œผ๋กœ ์‹œ๋„ํ–ˆ์ง€๋งŒ Maximum call stack size exceeded ๋” ๋งŽ์€ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

@Mitroright ์žฌ๊ท€ ์ ์œผ๋กœ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผํ•˜์ง€๋งŒ ์ ‘๊ทผ ๋ฐฉ์‹์ด ์ •ํ™•ํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋Š” Vue๊ฐ€ ๋ฐฐ์—ด์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ geoJsonData ์†์„ฑ์„ ๊ตฌ์„ฑ ๋ถˆ๊ฐ€๋Šฅ์œผ๋กœ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์€ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค.

function makeArrayNonConfigurable(objects)
{
    objects.forEach((obj) =>
    {
        Object.keys(obj).forEach((key) =>
        {
            Object.defineProperty(obj, key, { configurable: false });
        });
    });
}

์šฐ๋ฆฌ๋Š” ํ•œ ๋‹จ๊ณ„๋งŒ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ํ•ด์•ผ ํ•  ์ „๋ถ€์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. Vue๋Š” ์ค‘์ฒฉ๋œ ๊ฐ์ฒด ์†์„ฑ์„ ์ฐพ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ์„ฑํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ๋œ ์†์„ฑ์—์„œ ๋ฐฐ์—ด ๋‚ด๋ถ€์˜ ๊ฐœ์ฒด๋ฅผ ๋ณด๋Š” ๊ฒƒ ๊ฐ™์œผ๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ 10,000๊ฐœ์˜ ๊ฐœ์ฒด๋ฅผ ํ†ตํ•ด ์ด ๋ฐฐ์—ด์„ ์ฒ˜์Œ ํ†ต๊ณผํ•  ๋•Œ ๋ช‡ ์ดˆ ์ •๋„ ํœ˜์ “๋Š”๋‹ค๊ณ  ๋งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋น„์šฉ์˜ ์ผ๋ถ€๋กœ ๊ฐ„์ฃผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์†”์งํžˆ ๋งํ•ด์„œ, ๋‚˜๋Š” ๊ทธ ๊ฐ์ฒด๋ฅผ ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค(์ €๋Š” ์ƒ์„ฑ์ž์—์„œ ํ”„๋ก์‹œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค). ๊ทธ๋Ÿฐ ๋‹ค์Œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ์ˆ˜๋ช… ๋™์•ˆ ํ•œ ๋ฒˆ ์ด์ƒ ๋กœ๋“œํ•˜๋Š” ๊ฒฝ์šฐ ๊ณ ์œ  ID๋กœ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์บ์‹ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ธฐ๊ฐ„. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์‹ค์ œ๋กœ ๋””์ž์ธ ์„ธ๋ถ€ ์‚ฌํ•ญ์ด๋ฉฐ ๊ท€ํ•˜์˜ ๋ฌธ์ œ์™€ ์ •ํ™•ํžˆ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.
https://medium.com/@deadbeef404/tell -vue-js-to-stop-wasting-time-and-render-faster-7c3f7d2acaab

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ธฐ๋Šฅ์„ ๋งŒ๋“œ์‹ญ์‹œ์˜ค.

import Vue from 'vue';

const Observer = (new Vue()).$data.__ob__.constructor;

export function makeNonreactive(obj) {
    obj.__ob__ = new Observer({});
}

์•ˆ๋…•ํ•˜์„ธ์š” @Mitoright์ž…๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ ์ด ๊ธฐ์‚ฌ๋Š” vue-nonreactive ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฐจ์ด์ ์€ ์ฝ”๋“œ๋ฅผ ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์‚ฌ์šฉํ• ์ง€( vue-nonreactive ) ๋„์šฐ๋ฏธ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ• ์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ vue-nonreactive ๋Š” ์ด ๋ฌธ์ œ ์„ค๋ช… ์ƒ๋‹จ์˜ ์—…๋ฐ์ดํŠธ ์˜ค๋ฅธ์ชฝ์— ์–ธ๊ธ‰๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

vue-devtool์ด ๋‹ค์‹œ ์—…๋ฐ์ดํŠธ๋˜๋ฉด์„œ https://github.com/vuejs/vue/issues/2637#issuecomment -434154442๊ฐ€ vue-devtool์„ ๋‹ค์‹œ ์ถฉ๋Œํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

vue-nonreactive ๊ฐ™์€ ์†”๋ฃจ์…˜์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค ๐Ÿ˜†

__ob__ ์—ด๊ฑฐํ•  ์ˆ˜ ์—†๋„๋ก ํ•˜๋ ค๋ฉด defineProperty

vue-free.js

import Vue from 'vue'

const Observer = new Vue().$data.__ob__.constructor

function prevent(val) {
    if (val) {
        // Set dummy observer on value
        Object.defineProperty(val, '__ob__', {
            value: new Observer({}),
            enumerable: false,
            configurable: true,
        })
    }

    return val
}

// vue global
Vue.VUE_FREE = prevent

// window
global.VUE_FREE = prevent

// default export
export default prevent

๊ทธ๋ฆผ ๋‚˜๋Š” ์ด๊ฒƒ์— ๋Œ€ํ•œ 2 ์„ผํŠธ์™€ ํ•ด๊ฒฐ์ฑ…์„ ์ค„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ Freeze ๊ฐœ๋…๊ณผ ๊ฐ€์งœ ๊ด€์ฐฐ์ž๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•˜๋Š” ์œ ์‚ฌํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๋ฐ์ดํ„ฐ๋Š” ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜ค๊ณ  ์žฌ๊ท€์ ์ธ TreeNode ์‹œ๋‚˜๋ฆฌ์˜ค์ž…๋‹ˆ๋‹ค. ๋‚ด ํ”„๋กœ์ ํŠธ๋Š” ์ด ๊ฒฝ์šฐ์—๋„ vuex๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณธ ๋ฌธ์ œ์— ๋ ˆ์ด์–ด๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” vues object.keys ๋ฃจํ”„๋กœ ์ธํ•ด ์ง€์†์ ์œผ๋กœ Maximum call stack size exceeded ๋ฅผ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” Freeze๋ฅผ ์‹œ๋„ํ•˜๊ณ  ๊ฐ€์งœ VNode ๋‚ด๋ถ€์— ๋ฐ์ดํ„ฐ๋ฅผ ์„ค์ •ํ–ˆ์ง€๋งŒ ๋‘˜ ๋‹ค ์žฌ๊ท€ ๋ฌธ์ œ๋ฅผ ๋ง‰์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ ๊ฐ™์•˜์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋งˆ์นจ๋‚ด ๋’ค๋กœ ๋ฌผ๋Ÿฌ์„œ์„œ ๊ณ ์ „์ ์ธ Revealing Module Pattern์„ ์‚ฌ์šฉํ•˜์—ฌ "๋น„๋ฐ˜์‘์„ฑ" ์†์„ฑ์„ ๊ฐ์ŒŒ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ํด๋ž˜์Šค(ES6/typescript)์ด์ง€๋งŒ ์ผ๋ฐ˜ vue์—๋„ ๋™์ผํ•˜๊ฒŒ ์ ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import {  first, forEach } from 'lodash';

export class TreeNode {
    internalRefsInstance: () => { getParent: () => TreeNode; setParent: (parent: TreeNode) => void; getChildNodes: () => TreeNode[]; setChildNode: (childNode: TreeNode) => number; };

    get visitedDate(): string | undefined {
        return this._visitedDates.get(this.id) || undefined;
    }

    isSelectedTreeNode: boolean = false;
    showSubheader: boolean = false;
    showHelp: boolean = false;
    treeNodeIconName: string = 'empty';
    childTreeNodeCount: number = 0;

    constructor(public id: string,
        public componentName: string,
        private _visitedDates: Map<string, string>,
        public isActive: boolean = true,
        public nextFlow?: string,
        public prevFlow?: string,
        parent: TreeNode | undefined = undefined) {

        //invoke the internal refs module to create our static instance func to get the values from
        this.internalRefsInstance = this.nonReactiveModule();
        this.internalRefsInstance().setParent(parent);
    }
    nonReactiveModule = () => {
        let _parent: TreeNode | undefined = undefined;
        let _childNodes: TreeNode[] = [];
        const _getParent = (): TreeNode | undefined => {
            return _parent;
        };
        const _setParent = (parent: TreeNode | undefined): void => {
            _parent = parent;
        };
        const _getChildNodes = (): TreeNode[] => {
            return _childNodes || [];
        };
        const _setChildNode = (childNode: TreeNode): number => {
            if (!_childNodes) {
                _childNodes = [];
            }
            _childNodes.push(childNode);
            return _childNodes.length;
        };
        const returnObj = {
            getParent: _getParent,
            setParent: _setParent,
            getChildNodes: _getChildNodes,
            setChildNode: _setChildNode,
        };
        return () => { return returnObj; };
    }

    getParent(): TreeNode | undefined {
        return this.internalRefsInstance().getParent();
    }

    getChildNodes(): TreeNode[] {
        return this.internalRefsInstance().getChildNodes();
    }

    setChildNode(childFlow: TreeNode): void {
        this.childTreeNodeCount = this.internalRefsInstance().setChildNode(childFlow);
    }

    clone(parent: TreeNode | undefined = undefined): TreeNode {
        const newInstance = new TreeNode(this.id, this.componentName, this._visitedDates, this.isActive, this.nextFlow, this.prevFlow, parent);
        newInstance.showHelp = this.showHelp;
        newInstance.showSubheader = this.showSubheader;
        newInstance.isSelectedTreeNode = this.isSelectedTreeNode;
        forEach(this.getChildNodes(), (flow: TreeNode) => {
            newInstance.childTreeNodeCount = newInstance.internalRefsInstance().setChildNode(flow.clone(newInstance));
        });
        return newInstance;
    }

    setVisitedDates(visitedDates: Map<string, string>): void {
        this._visitedDates = visitedDates;
        forEach(this.getChildNodes(), (flow: TreeNode) => {
            flow.setVisitedDates(visitedDates);
        });
    }

    setAsSelected(setParent: boolean = true, setAllFirstChildren: boolean = true): void {
        this.isSelectedTreeNode = true;
        if (setAllFirstChildren) {
            const firstChildFlow = first(this.getChildNodes());
            if (firstChildFlow) {
                firstChildFlow.setAsSelected(false, true);
            }
        }

        if (setParent && this.getParent()) {
            this.getParent()!.setAsSelected(setParent);
        }
    }
    resetSelected(resetChildren: boolean = true): void {
        this.isSelectedTreeNode = false;
        if (resetChildren) {
            forEach(this.getChildNodes(), (flow: TreeNode) => {
                flow.resetSelected(resetChildren);
            });
        }
    }
}

๋‚ด ๊ฒฝ์šฐ์—๋Š” Computed๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋‚˜๋Š” ์—ฌ์ „ํžˆ ์ „์ฒด ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•˜๊ณ  ๊ณ„์‚ฐ๋œ ๊ฒƒ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋‚˜์—๊ฒŒ ๋ณด๋‚ด๋Š” ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ ์–ด๋„ ๊นŠ์€ ๊ฐ์‹œ์ž๊ฐ€ ๊ณ„์‚ฐ๋œ ๋ถ€๋ถ„ ์ง‘ํ•ฉ ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ณ  ์žˆ๋‹ค๋ฉด.

๋‚˜๋Š” ์ด๊ฒƒ์„ ๋‹ค์Œ ์ˆ˜์ค€์œผ๋กœ ๋Œ์–ด์˜ฌ๋ฆฌ๋ฉด ํ”„๋กœ์„ธ์Šค ์†๋„๋ฅผ ๋†’์ด๊ธฐ ์œ„ํ•ด ์ฃผ์ž…๋œ ๋น„์žฌ๊ท€ ๋„์šฐ๋ฏธ ๋˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์œ ์šฉํ•œ ํ”ผ๋“œ๋ฐฑ์ด ์žˆ์œผ๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด๋ฏธ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

https://github.com/vuejs/vue/issues/4384 ์—์„œ ๋ชจ๋“  ์„ธ๋ถ€ ์ •๋ณด๋ฅผ

์•ˆ๋…•ํ•˜์„ธ์š”, ์ €๋Š” ํŠนํžˆ ์ด ์ด์ „ ๋ฌธ์ œ๋ฅผ ์•Œ์ง€ ๋ชปํ•ด์„œ #10265๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
Vue๊ฐ€ Proxy๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ฏธ๋ž˜์— ๋Œ€๋น„ํ•˜๊ณ  Vue์™€ ํ˜ธํ™˜๋˜๋„๋ก ์กฐ์–ธํ•˜๋Š” ์†”๋ฃจ์…˜์ด ๋ฌด์—‡์ธ์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.
Object.defineProperty ๋ฅผ configurable: false Object.defineProperty ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ๊ธฐ์กด setter/getter๊ฐ€ ์žˆ๋Š” ์†์„ฑ์ด ๋ฐ˜์‘ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค).
์ด ๊ธฐ์ˆ ์„ Vue 3์—์„œ ๊ณ„์† ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
๊ฐ์‚ฌ ํ•ด์š”

@colin-guyon configurable: false ๋Š” ์•„๋งˆ๋„ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ https://github.com/vuejs/vue-next/blob/d9c6ff372c10dde8b496ee32f2b9a246edf66a35/packages/reactivity/src#/reactive59t ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ƒˆ๋กœ ์ œ์•ˆ๋œ Vue.observable ์ฒ˜๋Ÿผ ์†์„ฑ์ด ๋ฐ˜์‘ ๊ฐœ์ฒด์— ์„ค์ •๋˜๋ฉด ํ•ด๋‹น _new_ ๊ฐ’์ด ์˜ค์—ผ๋˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  _getter_๋Š” ์ด์— ๋Œ€ํ•œ ๋ฐ˜์‘ ํ”„๋ก์‹œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์บ์‹œ์— ์•„์ง ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์ƒˆ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋‹คํ–‰์Šค๋Ÿฌ์šด ์†Œ์‹์€ _that_ ๋ฐ˜์‘์„ฑ ํ”„๋ก์‹œ์—์„œ ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š” ํ•œ ๊ดœ์ฐฎ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ํ˜ธ๊ทธ ๋˜๋Š” ์ƒํ˜ธ ์šด์šฉ์„ฑ์ด ์šฐ๋ ค๋˜๋Š” ๊ฒฝ์šฐ ๊ฐ์ฒด๊ฐ€ ๋ฌด์—‡์ด๋“ ๊ฐ„์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฑฐ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ๋ชจ์Œ์ด๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ผ๋ถ€ ์™ธ๋ถ€ ๊ฐ์ฒด์— ๋Œ€ํ•ด ๋ฐ˜์‘์„ฑ์ด ์ ์šฉ๋˜์–ด์•ผ ํ•˜๋Š” ๋™์ž‘์„ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. โ€” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด _์•„๋ฌด๊ฒƒ๋„_ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์˜๋ฏธ์—์„œ Vue 3.x๋Š” ์‹ค์ œ๋กœ ์ด ๊ธฐ๋Šฅ์ด ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋งŽ์€ ๊ฒฝ์šฐ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ vue-next ์ฝ”๋“œ๋Š” ํ˜„์žฌ ๋ฒ„์ „์˜ Vue์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฐ˜์‘ํ˜•์—์„œ ๊ธฐํ˜ธ ํ‚ค๋ฅผ ์ œ์™ธํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
set val._isVue = true ๋Š” vue ๊ด€์ฐฐ ์ ˆ์ฐจ์—์„œ ๋ฒ—์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜ ์ €๋Š” Vue๊ฐ€ mapbox-gl์˜ ๋งต ์ธ์Šคํ„ด์Šค๋ฅผ ๊ด€์ฐฐํ•œ ํ›„ ์ด์ƒํ•œ ์ผ์ด ๋ฐœ์ƒํ•˜์—ฌ ๋งต์ด ๊ฐ€๋ฒผ์›Œ์ง€๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งŒ๋‚ฌ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งต ์ธ์Šคํ„ด์Šค๋Š” vue ์ธ์Šคํ„ด์Šค ๊ฐ„์— ์ „๋‹ฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. map._isVue = true ์ถ”๊ฐ€ํ•œ ํ›„ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

_isVue ๊ฐ€ ์‚ฌ์‹ค์ด๊ณ  ๊ฐ์ฒด๊ฐ€ Vue ๊ตฌ์„ฑ ์š”์†Œ ์ธ์Šคํ„ด์Šค๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ทธ๋ ‡์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Vue ๊ฐœ๋ฐœ ๋„๊ตฌ๊ฐ€ ๋„์ฒญ์— ๋ฌผ๋ฆด ๋•Œ๊นŒ์ง€ ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์‹ฌ๊ฐํ•œ ๋ถ€์ž‘์šฉ ์—†์ด ๋‚ด๊ฐ€ ๋ณธ ์œ ์ผํ•œ ํ•ดํ‚น์€ vue-nonreactive ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ OP์˜ ์ ‘๊ทผ ๋ฐฉ์‹์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ V3์˜ ๋Œ€์ฒด ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@ HunderlineKshallowRef,shallowReactive,markRaw

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰