Search code examples
reactjsvue.jsvuejs3vue-reactivity

Can't figure out reactivity in Vue


I'm more familiar with React and I've been try to port this component from React to Vue for a project. Everything about my solution seems to be working except when I update the ref value in the parent component, that change isn't propagated to the child component. The passed value is updated in the child, but its dependents aren't updated.

I've tried using watch, watchEffect, and computed to update the currentPercent variable but none of it seems to work. The only thing that did work was adding a key to the GaugeCircle component, but that rerenders the entire component, so I don't get the nice transition animation when the value is updated. Any suggestions how to get this to work?

Here's my code: StackBlitz example


Solution

  • You need to update your script to the following

    <script setup lang="ts">
    import { cn } from '../utils';
    import { computed, toRefs } from 'vue'
    
    interface Props {
      max: number;
      value: string | number;
      min: number;
      gaugePrimaryColor: string;
      gaugeSecondaryColor: string;
      className?: string;
    }
    
    const props =
      defineProps<Props>();
    const { max, value, min, gaugePrimaryColor, gaugeSecondaryColor, className } = toRefs(props)
    
    const circumference = 2 * Math.PI * 45;
    const percentPx = circumference / 100;
    
    const currentPercent = computed(() => ((value.value - min.value) / (max.value - min.value)) * 100);
    </script>
    

    Explanations:

    • you need to have toRefs to keep the reactivity of your props when you restructure them, here is an article about that topic
    • the computed is needed to recompute the variable properly each time
    • value can have a single type but you need to use .number on the v-model and something else I suppose? Not sure what's wrong on top of that