[Vuejs]-Property or method "_" is not defined on the instance but referenced during render

3👍

✅

Accessing _ in template

Assuming you’re using the Options API, importing _ does not automatically make it available to the template (as @tao pointed out in his answer). The template can only access fields exposed via the component options (e.g., data, props, methods, computed, etc.) in addition to a few allow-listed globals (Vue 2 allowed globals, Vue 3 allowed globals).

Using _.debounce

_.debounce‘s first argument is a function reference:

_.debounce(submit(props.row, props.index), 100) // ❌ calls `submit()`, and passes the result to _.debounce()

To create a debounced submit, pass the submit-reference as an argument to _.debounce like this:

_.debounce(submit, 100)

You technically could invoke the debounced function immediately:

_.debounce(submit, 100)(props.row, props.index)


but don’t do that in the template (see reason below).

Using a debounced event handler for v-on

When the value of the v-on directive (@ for shorthand) is an expression (as in your case), the template compiler automatically wraps the expression in a function, so this:

@change="_.debounce(submit, 100)"


essentially becomes:

@change="($event) => _.debounce(submit, 100)"


which would have no effect, since debounce doesn’t invoke the wrapped function itself.

You might be tempted to call the function immmediately in:

@change="_.debounce(submit, 100)(props.row, props.index)"


but that creates a new debounced function on every event, which defeats the debouncing.

Solution

Create a debounced function in the <script> part of the SFC that could then be used as the v-on value:

Options API:

<script>
import { debounce } from 'lodash'

export default {
  created() {
    this.debouncedSubmit = debounce(this.submit, 100)
  },
  methods: {
    submit(row, index) {/*...*/}
  }
}
</script>

Composition API in setup() option:

<script>
import { debounce } from 'lodash'

export default {
  setup() {
    const submit = (row, index) => {/*...*/}

    return {
      debouncedSubmit: debounce(submit, 100),
    }
  }
}
</script>

Composition API in <script setup>:

<script setup>
import { debounce } from 'lodash'

const submit = (row, index) => {/*...*/}
const debouncedSubmit = debounce(submit, 100)
</script>

Template:

<cost-code-field @change="debouncedSubmit(props.row, props.index)" />

demo

đŸ‘€tony19

1👍

Any var referenced in template is prefixed with this under the hood. Which means you can’t reference global vars in the template, unless they’re expressly declared in its context.

Simply put, the template context is an object. If you don’t define a particular key and don’t assign it a particular value, it’s going to be undefined.

Probably the most concise way of exposing globals to the template is using computed:

// ...
  computed: {
    _: () => _
  }
// ...

In Composition API, the simplest way to expose globals is to add them in the object returned by setup:

export default {
  // ... 
  setup() {
    //...
    return {
      _,
      //...
    }
  }
}
đŸ‘€tao

Leave a comment