menu

Questions & Answers

How to pass refs from parent component to child component? Without using Typescript?

I have an App.vue with the property "clicked" that I'm trying to pass to child components.

App.vue

<template>
  <NavBar :clicked="clicked"/>
  <BackDrop :clicked="clicked"/>
  <SideDrawer :clicked="clicked" />
  <router-view></router-view>
</template>
<script>
import { ref } from "vue";
import NavBar from "./components/Navbar/NavBar.vue";
import BackDrop from "./components/Backdrop/BackDrop.vue";
import SideDrawer from "./components/Sidedrawer/SideDrawer.vue";
export default {
  name: "App",
  components: { NavBar, BackDrop, SideDrawer },

  setup() {
    const clicked = ref(false);

    return { clicked };
  },
};
</script>
export default App;

so the child components can be rendered conditionally like:

SideDrawer.vue

<template v-if="clicked">
  <div class="sidedrawer"></div>
</template>
<script setup>
</script>

Did I pass the "clicked" ref properly in the "App.vue"?

If I did, how do you access them in the child component? I've already googled and looked at a bunch of StackOverflow posts but the majority of them seem to use, "defineProps()", like this code:

const props = defineProps({
  msg: String,
  user: Object,
});

// Destructuring props
let { name, lastname } = props.user;
</script>

but I'm not using Typescript so this won't work for me.

What is the "non-typescript" way of passing props? Do you need to use Typescript to pass props?


EDIT:

Even when I implement Typescript and use this code:

SideDraw.vue

<template v-if="clicked">
  <div class="sidedrawer">
    <h1>{{ props.clicked }}</h1>
  </div>
</template>
<script setup>
const props = defineProps({
  clicked: boolean,
});
</script>

I get the errors:

'defineProps' is not defined.eslintno-undef
'boolean' is not defined.eslintno-undef

...

I gathered from this Github thread to set global variables so I did this, but it still doesn't work.

babel.config.js

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
    globals: {
      defineProps,
      defineEmits,
      defineExpose,
      withDefaults
    }
  }
}
Comments:
2023-01-22 23:10:16
You mixed up JS and TS syntax. defineProps({ msg: String, user: Object, }) - this is valid JS, String and Object are constructors. defineProps({ clicked: boolean, }) - this is a mistake, you tried to use TS type (lower case) where runtime value is expected.
Answers(3) :

No, you do not need TypeScript when defining props. TypeScript is a superset of JavaScript so any TypeScript is also valid JavaScript.

When using <script setup>, you use defineProps to define which props a component can accept. You do not need to declare or import it anywhere as it is a compiler macro. If ESlint is complaining, then it is not configured properly. Add the following to your eslint configuration file.

module.exports = {
    env: {
        'vue/setup-compiler-macros': true
    }
}

In each of your child components you need to accept "clicked" as a property.

<script setup>
const props = defineProps(['clicked'])
</script>

or (using runtime types - this is not Typescript as pointed out by @Estus);

<script setup>
const props = defineProps({
  clicked: Boolean
})
</script>

In your App.vue, you need to pass a value to the prop as follows;

<script setup>
import { ref } from "vue";

const clicked = ref(false);
</script>
<template>
    <NavBar :clicked="clicked"/>
    <BackDrop :clicked="clicked"/>
    <SideDrawer :clicked="clicked" />
    <router-view></router-view>
</template>

If you are not going to use <script setup>, then you can define which props to accept as follows;

export default {
  name: "NavBar",
  props: ['clicked']
};

or (using runtime types - this is not Typescript as pointed out by @Estus);

export default {
  name: "NavBar",
  props: {
    clicked: Boolean
  }
};
Comments:
2023-01-22 23:10:16
{ clicked } syntax is incorrect.
2023-01-22 23:10:16
clicked: Boolean
2023-01-22 23:10:16
It's JS, see the comment above
2023-01-22 23:10:16
These are runtime types, not TS, it's the same as with regular props options. You can omit them like that too vuejs.org/guide/essentials/component-basics.html#passing-pro‌​ps
2023-01-22 23:10:16
Updated to include both approaches

In JavaScript you have two common ways of defining props, either with just array of prop names like so:

const props = defineProps([ 'clicked', 'someOtherProp' ]);

Or much more preferred(due to saving between hours and days of troubleshooting) is to define each prop with object as so:

  const props = defineProps({
    clicked: { type: Boolean, default: false, required: true },
  });

Here is the relevant section of docs: https://vuejs.org/guide/components/props.html#prop-validation

You need to defineProps code in your child component and not in you app.vue. Also dont forget to use script setup so that you dont have to import defineprops. from vue.