0

I have a logical component that doesn't have a template, but only stores the active/not active state.

So. It works, but without ID.

I use the id when necessary to make the block's state consistent with other blocks that may be active.

For example, when I click on a menu or product catalog button, their body is displayed in the same place. To avoid layering, I say that when the menu is enabled, the product catalog is hidden. And vice versa. The catalog turned on - the menu was hidden.

For each entity that can be active, I assign an id, and a list of exclusion ids. The list is deactivated by id.

The component does not see that the Service changes its state. In devtools, I need to click the "refresh" button to see the new state of the service.

Here is the code.

Menu.vue template:

<template>
  <section class="menu" :style="{'--sticky-bottom': StickyBottom + 'px'}">
    <CanActive id="header-menu" :excludeIds="['header-catalog']" v-slot="{isActive, toggleShow}">
      <div class="menu__bg" :class="{active: isActive}"></div>
      <button class="menu__btn"
              :class="{active: isActive}"
              @click="toggleShow"
      >
        <span></span>
      </button>
      <MenuBody class="menu__body"
                :class="{active: isActive}"
                :style="{'--sticky-bottom': StickyBottom + 'px'}"
      />
    </CanActive>
  </section>
</template>

CanActive.vue:

<template>
  <div class="logical">
    <slot :isActive="IsActive" :toggleShow="toggleShow"></slot>
  </div>
</template>

<script lang="ts">
import {Component, Vue} from "~/tools/version-types";
import {Prop} from "vue-property-decorator";
import {canActiveViewService} from "@shared/services/ui/view/canActive.view.service";

@Component({
  name: "CanActiveComponent",
})
export default class CanActiveComponent extends Vue {
  @Prop({default: false}) startValue: boolean;
  @Prop({default: null}) id: string | null;
  @Prop({default: []}) excludeIds: string[];

  isShowInner: boolean = false;

  mounted() {
    this.IsActive = this.startValue;
  }

  toggleShow() {
    this.IsActive = !this.IsActive;
  }

  close() {
    this.IsActive = false;
  }

  get Service() {
    return canActiveViewService;
  }

  get IsActive() {
    if (this.id) {
      return this.Service.state[this.id];
    } else {
      return this.isShowInner;
    }
  }

  set IsActive(value) {
    if (this.id) {
      this.Service.setIdValue(this.id, value, this.excludeIds)
    } else {
      this.isShowInner = value;
    }
  }
}
</script>

<style lang="scss" scoped>
.logical {
  display: contents;
}
</style>

CanActiveViewService:

import {reactive} from "vue";

class CanActiveViewService {
    // reactive - try to fix problem
    state: Record<string, boolean> = reactive({});

    setIdValue(id: string, val: boolean, excludedIds: string[]) {
        this.state[id] = val;
        excludedIds.forEach((id) => {
            this.state[id] = false;
        });

        console.dir(this.state);
    }
}

export const canActiveViewService = reactive(new CanActiveViewService());

This trick works on Vue 3, why doesn't it work here?

I am using Vue 2 and Nuxt.

5
  • 2
    It's not a good idea to use classes with composition api, too much pitfalls without any benefits. Probably not specific to classes. You should list object keys in Vue 2 explicitly in order to make them reactive, reactive({}) won't work. Commented Oct 4, 2022 at 13:32
  • Our architecture is too complex to be stored in VUEX or other state managers. We also have a core that is used in different projects and frameworks, and it is desirable to reuse it. So, i need do this way Commented Oct 4, 2022 at 13:39
  • 1
    I don't talk about reuse. But the use of classes specifically, e.g. stackoverflow.com/questions/67894487/… . Everything you write as CanActiveViewService can be written with plain objects and functions with less problems. As for this problem, it's what's described in the answer indeed Commented Oct 4, 2022 at 13:59
  • Oops, I thought I answered your comment. I got it, thanks for the comment, I'll note :) Commented Oct 7, 2022 at 17:08
  • No problems, you're welcome Commented Oct 7, 2022 at 17:16

1 Answer 1

1

Oh God, I got it 🤦‍♂️

A very important difference between Vue 2 and Vue 3 is that in Vue 2 we have to use Vue.set(object, id, val); for reactivity.

That is, the service code should look like this.

import {reactive} from "vue";
import {Vue} from "~/tools/version-types";

class CanActiveViewService {
    state: Record<string, boolean> = {};

    setIdValue(id: string, val: boolean, excludedIds: string[]) {
        Vue.set(this.state, id, val);
        excludedIds.forEach((id) => {
            Vue.set(this.state, id, false);
        });
    }
}

export const canActiveViewService = reactive(new CanActiveViewService());

Now it works.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.