0
votes

Hi I'm new to vue and am trying to understand its one-way data bind model component registration and passing props.

In my index.js I have my parent component in which I want to render a single child right now

import Vue from 'vue'
import StyledTitle from './components/StyledTitle'

new Vue({
  el: '#app',
  components: {
    StyledTitle,
  },
})

Child Component is StyledTitle.js

import Vue from 'vue'
import styled from 'vue-styled-components'

const StyledTitle = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: #ff4947;
  &:hover,
  &:focus {
    color: #f07079;
  }
`

Vue.component('styled-title', {
  props: ['text'],
  components: {
    'styled-title': StyledTitle,
  },
  template: `<StyledTitle>{{ text }}</StyledTitle>`,
})

export default StyledTitle

Finally my HTML is which I expect to render a red Hi

<div id="app">
   <styled-title text="Hi"></styled-title>
</div>

The HI is not showing up though and the props value is undefined. Coming to this from react so wondering why this isnt working, thanks!

Ps screenshot of my vue devtools enter image description here

1
@MarkMeyer no errors in console that are relevant to the app. I'll add a screenshot of my vue devtools though. const StyledTitle = styled.h1`` is how you declare a styled component. - gwar9
Is there a reason you want to pass the text as a prop instead of just setting it in the default slot? - Phil
@Phil Component def works if I just pass Hi between the opening and closing tags but I wanted to get props to work for future cases where I may have more dynamic content than just "Hi" coming from an API or some other data object - gwar9

1 Answers

2
votes

The issue is that your StyledTitle.js file exports a normal styled <h1> component which uses a default slot for its content instead of your custom component that accepts a text prop.

If you're still keen on using a prop-based component, you need to export that instead of the one from vue-styled-components. You should avoid global component registration in this case too.

For example

// StyledTitle.js
import styled from 'vue-styled-components'

// create a styled title locally
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: #ff4947;
  &:hover,
  &:focus {
    color: #f07079;
  }
`

// now export your custom wrapper component
export default {
  name: 'StyledTitle',
  props: ['text'],
  components: {
    Title, // locally register your styled Title as "Title"
  },
  template: `<Title>{{ text }}</Title>`,
})

Given your component doesn't maintain any state, you could make it purely functional. Using a render function will also help, especially if your Vue runtime doesn't include the template compiler (which is the default for most Vue CLI apps)

export default {
  name: 'StyledTitle',
  functional: true,
  props: { text: String },
  render: (h, { props }) => h(Title, props.text)
}