0

I am using vue3.As shown in the below posted code, in the class test.js should be a composable class. i want this class to reflect the change of state in another vue-component. in other words, the value of state changes as eminent in the code, i want to reflect the updated value of state in a vue-component. i want the vue-component to display the different states set in the test.js

to achieve that, i made the state of type ref as shown in the code.

in the vue-component as shonw below, i call and display the contents of state = useState() in ' state: {{state }}' and i expect the states to be displayed are not-satrted,started, processing and successful. But that does not happend.

how can i print updated values of state from test.js in a vue-component please.

vue-component:

<template>
    <span> state: {{state }}</span>
</template>

<script>
    import { useStates } from '../xxx/xxx/Composables/test.js';
    const state = useStates();
    

test.js

import { ref, onMounted, onUnmounted } from 'vue'

// by convention, composable function names start with "use"
export function useStates() {
  let state = ref('not-satrted')

  setTimeout(() => {
    state.value = 'started'
  }, 1000);

  setTimeout(() => {
    state.value = 'processing'
  }, 2000);

  setTimeout(() => {
    state.value = 'successful'
  }, 3000);
  // expose managed state as return value
  return state 
}
Amrmsmb
  • 1
  • 27
  • 104
  • 226
  • 1
    you've tagged this both `vuejs2` AND `vuejs3` - perhaps that's the issue, the two versions are quite different – Jaromanda X Aug 17 '23 at 12:51
  • 1
    `digitizationStatus` needs to be made reactive _before_ you export it if you want the value updated in the .js file to be reflected in the vue component, not after. The .js file should be made into a [composable](https://vuejs.org/guide/reusability/composables.html). Or if a store like [Pinia](https://pinia.vuejs.org/) makes sense for your app you can just use that – yoduh Aug 17 '23 at 12:52
  • The question fails to provide https://stackoverflow.com/help/mcve , it deals with truncated snippets and doesn't show the big picture. "how i export the digitizationStatus:" - export from which file? ".js" - which file is that? Currently it looks like you have some basic reactivity problem. First of all, preferably not use classes because they have several pitfalls, https://stackoverflow.com/a/76247596/3731501. In case you modify non-reactive `digitizationStatus` variable from inside a class, there's no way how you can do that here `digitizationStatus =` in a sane way, should have been a ref – Estus Flask Aug 17 '23 at 12:54
  • @EstusFlask would you please tell me how can i create a js-class in a reactive way?i read the official docs of vue. and created examples with reactivity but as for my understanding the reactivity works only with vue-components not js-classes, am i right? – Amrmsmb Aug 17 '23 at 12:57
  • That *could* depend if you're using `vuejs2` or `vuejs3` - as you have tagged both, the answer is difficult – Jaromanda X Aug 17 '23 at 13:03
  • @yoduh how can i make `digitizationStatus` reactive while it is in a js class please? – Amrmsmb Aug 17 '23 at 13:04
  • @JaromandaX i modified the tags – Amrmsmb Aug 17 '23 at 13:04
  • Vue 3 supports reactivity in classes but makes this impractical. You preferably shouldn't as it's a footgun in several ways, see the link above. If your app already uses classes for some reasons then you can integrate them with vue reactivity through generic approaches (pub/sub) – Estus Flask Aug 17 '23 at 13:56
  • @EstusFlask would you please tell me based on your experience what is kept the js class ‘ DigitizePolygonInteractions.js’ as it is and used ‘event-bus’…would that be an efficient solution please? – Amrmsmb Aug 17 '23 at 14:47
  • @JaromandaX would you please tell me based on your experience what is kept the js class ‘ DigitizePolygonInteractions.js’ as it is and used ‘event-bus’…would that be an efficient solution please? – Amrmsmb Aug 17 '23 at 14:48
  • 1
    The class can just expand `mitt` or any other third-party event emitter or implement pubsub pattern in any other way, so it would be possible to subscribe to events with `on()` from the outside and emit them with `emit()` from the inside. There's more than one way to do this, this is just one that is generic and doesn't enforce a class to hack around Vue quirks – Estus Flask Aug 17 '23 at 14:54
  • @EstusFlask thanks for the precious point of view. However, do you think that js class ‘ DigitizePolygonInteractions’ can be converted into compsables? – Amrmsmb Aug 17 '23 at 15:00
  • @EstusFlask thanks for the precious point of view. However, do you think that, that js class ‘ DigitizePolygonInteractions’ can be converted into compsables? – Amrmsmb Aug 17 '23 at 15:00
  • 1
    I'd naturally recommend to do this, unless this is some framework-agnostic piece of code that isn't tied to the usage in Vue. It's often that the choice of OOP is just a matter of taste and not a real design necessity, so a class can be plainly rewritten as factory function – Estus Flask Aug 17 '23 at 15:20
  • @EstusFlask according to the official docs, comparable can only be developed when composition api is used, while in my project options api is used…can I still convert the js class into compsable please? – Amrmsmb Aug 17 '23 at 16:08
  • It would make it it more straightforward to understand how it works but not necessary, options api is translated to composition setup function under the hood in V3 afaik. You can do `myData: useMyData()` in data() function instead of `const myData = useMyData()` in setup – Estus Flask Aug 17 '23 at 16:13

2 Answers2

0

You have to understand the principles of react vue reacts work on object cell references you need to use refs from the beginning because there is no power to allow response tracking from variables set digitizationStatus to ref like this:

class ... {
  digitizationStatus = ref()
}
...
if (this.#getOperation() === BtnDigitizePolygonConstants.CONST_STRING_DIGITIZE.description) {
    this.#enableDigitization()
    digitizationStatus.value = BtnDigitizePolygonConstants.CONST_DIGITIZATION_STATE_SUCCESSFUL.description; //<====
}
Tachibana Shin
  • 2,605
  • 1
  • 5
  • 9
  • Is it possible to user ‘ref’ in .is class please? – Amrmsmb Aug 17 '23 at 14:26
  • This will result in a disaster in case class instance is used in a component and becomes reactive, this includes using it in data() – Estus Flask Aug 17 '23 at 14:57
  • @EstusFlask vue's new react-principles don't care that as long as you run something like get proxy in the `effect` lifecycle it's valid – Tachibana Shin Aug 18 '23 at 00:32
  • people often ask us if they should use `ref` here, and our answer is always `wherever you want to treat it as a variable` – Tachibana Shin Aug 18 '23 at 00:34
  • @TachibanaShin I mean this issue, https://stackoverflow.com/questions/73939248/vue-class-objects-with-internal-ref-breaks-with-reactive/73940781#73940781 . Refs are unwrapped inside reactive object in uncontrollable manner, including class instances – Estus Flask Aug 18 '23 at 01:35
  • @EstusFlask why do we need to wrap instance in a reactive again (`reactive(new Class())`) it's really redundant in react system – Tachibana Shin Aug 18 '23 at 03:15
  • this library uses `class` and it even deeply integrates `effect` of `@vue/reactivity` into classes with no problem even if they run in node.js or vue – Tachibana Shin Aug 18 '23 at 03:17
  • @TachibanaShin It's not redundant in the first place. This is necessary if class fields need to be reactive. This problem have occurred to me in several unrelated questions, it's not made-up. – Estus Flask Aug 18 '23 at 08:43
  • anyway I don't think event bus is a good idea for this – Tachibana Shin Aug 18 '23 at 10:30
  • if worst case happen we can use `customRef` for this – Tachibana Shin Aug 18 '23 at 10:33
0

As per your requirement you can use Event Bus to pass the data from JavaScript file to Vue.

In your main.js :

import Vue from 'vue';
export const eventBus = new Vue();

And then in your DigitizePolygonInteractions.js file, You can emit the digitizationStatus using $emit method on eventBus.

import { eventBus } from './main.js';

// Your other code logic will come here
{
  eventBus.$emit('digitizationStatusUpdated', digitizationStatus);
}

And then you can listen this event in your vue-component :

In Vue component script section

import { eventBus } from './main.js'; // Adjust the path accordingly

export default {
  data() {
    return {
      digitizationStatus: ''
    }
  },
  created() {
    eventBus.$on('digitizationStatusUpdated', (status) => {
      this.digitizationStatus = status;
    })
  }
}

The above solution is in Vue 2, But if you are looking for a same workaround in Vue 3, You can achieve that using external library tiny-emitter. Give a read to this documentation.

Debug Diva
  • 26,058
  • 13
  • 70
  • 123