How to make ref arrays work in Vue 3 composition API when passing them to child components?

Viewed 8908

I have the following todo app with these two components: App and Todo

App.vue

<template>
  <div class="todo-list">
    <div :key="index" v-for="(todo, index) in state.todos">
      <Todo :todo="todo" :state="state" />
    </div>
  </div>
</template>

<script>
import { reactive } from '@vue/composition-api';
import Todo from './components/Todo.vue';

export default {
  components: {
    Todo
  },
  setup() {
    let state = reactive({
      todos: [
        { text: 'Learn about Vue', isCompleted: false },
        { text: 'Meet friend for lunch', isCompleted: false },
        { text: 'Build really cool todo app', isCompleted: false }
      ]
    });

    return { state };
  }
};
</script>

Todo.vue

<template>
  <div class="todo">{{ todo.text }}<button @click="deleteTodo">x</button></div>
</template>

<script>
export default {
  props: ['todo', 'state'],
  setup({ todo, state }) {
    const deleteTodo = () => {
      state.todos = state.todos.filter(t => t != todo);
    };

    return {
      deleteTodo
    };
  }
};
</script>

The deleteTodo function works fine in the Todo.vue component, however, I would like to know if it's possible not to pass a state object but rather use a ref() like so and pass the todos...

So in App.vue

//...
    let todos = ref({[
        { text: 'Learn about Vue', isCompleted: false },
        { text: 'Meet friend for lunch', isCompleted: false },
        { text: 'Build really cool todo app', isCompleted: false }
      ]);
//...

Instead of:

//...
   let state = reactive({
      todos: [
        { text: 'Learn about Vue', isCompleted: false },
        { text: 'Meet friend for lunch', isCompleted: false },
        { text: 'Build really cool todo app', isCompleted: false }
      ]
    });
//...

However, when I try to do this... the child is unable to filter the deleted todo and re-assign to the todos variable. This doesn't work.

Any ideas how I can make it work with ref?

1 Answers

you are using ref in wrong way. ref means to be used with reactive primitive values like numbers and string etc. while reactive means to be used for reactive objects.

you can use arrays as well with ref. but you should not wrap arrays within an object to use inside ref

The correct statement would be

let todos = ref([      
        { text: 'Learn about Vue', isCompleted: false },
        { text: 'Meet friend for lunch', isCompleted: false },
        { text: 'Build really cool todo app', isCompleted: false }
    ])

then you can filter as you were doing it. only now you have to refer arrays like todos.value. kind of you already doing state variable.

https://v3.vuejs.org/guide/reactivity-fundamentals.html#declaring-reactive-state

Related