JSFiddle - React, Tailwind, and code Playground

VueJS 3 nested ref

by shenron

HTML

<script src="https://unpkg.com/vue@next"></script>

<div id="app">

</div>

JavaScript

const {
  ref,
  computed,
  createApp,
  defineComponent,
  provide,
  inject,
  watchEffect,
} = Vue;

const OptionsSymbol = Symbol('options');

const provideOptions = () => {
  const options = ref([])
  
  const addOption = (option) => {
    const _options = inject(OptionsSymbol, options);
    
    _options.value.push(option); 
  }
  
  return {
    provide() {
      return provide(OptionsSymbol, options);
    },
    addOption,
    options: inject(OptionsSymbol, options),
  }
}

const VOption = defineComponent({
  template: '<option ref="root" :value="opt.value">{{ opt.label }}</option>',
  props: ['value', 'label'],
  setup(props) {
    const { addOption } = provideOptions();
    
    const root = ref();
    
    const opt = {
      value: props.value,
      label: props.label,
      root
    };
    
    addOption(opt);
    
    return {
      opt,
      root,
    }
  }
})


const VSelect = defineComponent({
  template: `
    <select><slot /></select>
    nb options: {{ nbOptions }}
  `,
  setup() {
    const { provide, options } = provideOptions();
    
    provide();
    
    const nbOptions = computed(() => options.value.length);
    
    watchEffect(() => {
      debugger;
      options.value.forEach((opt) => console.log(opt.value.label))
    });
    
    return {
      nbOptions,
    }
  }
})

const App = defineComponent({
	template: `<VSelect>
    <VOption :value="0" label="-" />
    <VOption :value="1" label="First Value" />
    <VOption :value="2" label="Second Value" />    
  </VSelect>`,
  components: {
  	VSelect,
    VOption
  },
})

createApp(App).mount('#app')