What causes Vue props to equal [object Object] in the DOM? - javascript

While inspecting the DOM for a Vue app in the Chrome console, I noticed there was an element with the attribute content=[object Object]. In the code, it's because that component was passing an object as a content prop to its child, and for some reason this was showing up in the DOM.
The component in question:
<custom-component :content="obj" />
I inspected other areas of the code that are also passing object props down to their children, and noticed that those props were absent from the DOM. Unfortunately, I could not find any significant differences that could be responsible for the discrepancy. Since I am trying to also hide content=[object Object] from the DOM, I was wondering what in Vue determines this behavior?
I tried to reproduce the behavior in this jsfiddle. However due to my question I can't figure out how to properly do that, and the content prop is absent from the DOM there. Any help would be greatly appreciated.

This is most likely because you haven't defined it as a prop on the relevant component. If it isn't defined as a prop then it'll just be converted to a string and added as an attribute to the outermost element of the component.
If your component does define this prop then check its template to see whether it is adding this attribute to its outermost element itself. If it's calling out to some other component at the root of the template then you'll similarly need to check whether that component defines this prop.

The dom will register the prop as [object Object] if the component hasn't been registered properly, ie
import ExampleComponent from '...'
export default {
components: { ExampleComponent },
}

Related

Fix React Warning: Unknown prop on <> tag. Remove this prop from the element

I got a warning:
Warning: Unknown props `onClickProp`, `excludedClickClasses`
on <div> tag. Remove these props from the element. For details,
see `https://...react-unknown-prop in div` (created by myTable)
I did some search, but still can't find a solution. I didn't use these two props in myTable. in myTable, I just passed it in the child component myTableRow.
I tried to define props types and default props, but it doesn't work. Can I get some help?
Thanks!
That warning is happening because you're passing onClickProp, etc to a div element in one of your components.
A div element by default doesn't have those props, so these props would be no-op, and as such a warning.
You can find the detailed documentation here.

Putting an element inside Svelte Component

What does putting an element inside Svelte Component mean?
Eg. this code:
const target = document.createElement('div');
// render the component in the new element
const sample = new Sample({ target });
Like, here, in the given linked code, author is doing that:
https://github.com/rspieker/jest-transform-svelte/blob/master/example/test/Sample.spec.js#L8
What does this do? Is it putting Svelte component inside a div? Is it a Svelte syntax to put the element inside the constructor of the Svelte component?
Yes, that snippet is initializing the Svelte component named Sample and rendering it within the target div. The target property of a Svelte component constructor's options parameter is the only required property.
For more information, check out Svelte's components documentation.
It is the place where in your document the component will be rendered. Normally you would use a very specific location like body or a div with a certain id.
In this case however you are not actually rendering a page but merely testing a component so it doesn't matter where the div is.
You can find more info on testing with Jest here https://jestjs.io/

Vue: Reasons to use props instead of referencing parent data?

In VueJS, I have seen different ways of accessing parent properties from a component. Say I want to use the parent property items in my component.
First way
The component has a props value bound to a parent property:
.js
Vue.component("example", {
template: "<div></div>",
props: ["myItems"]
});
.html
<example v-bind:my-items="items"></example>
Second Way
The child component accesses a parent's properties directly, like this:
this.$parent.items
Question
Is there a reason to use the more elaborate first method over the second? Is there an overhead to "duplicating" data like that, vs. accessing it directly when needed?
The props should be mutated in the parent component, according to the official doc :
All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to understand.
In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console
So in order to update props from child component you should use this.$emit event and send the new value in order to handle the update in the parent one.

How to enable tracking deep changes in component props

I have a component who initialized like this
<custom :opts="{map: false}"></custom>
and there is HTML similar to this
<template id="custom">
<div v-if="opts.map">
I'm awesome
</div>
<button v-on:click="show"></button>
</template>
where
function show(){
this.opts = {map:true} // (1) <-- This is working and I could see hidden div
this.opts.map = true // (2) <-- For some reason not working
Vue.set(this.opts, 'map', true) // (3) <-- Still not working
}
So my question is why variant 2 doesn't work and what should I change to make my control react to value reset on a button click. Or a proper explanation why (1) is working, but (2) isn't - also will be accepted as an answer.
The real problem with the code (all 3 versions) is changing a component's property from within a component. In idiomatic Vue, only the parent should change properties. If a component needs to effect a change, it should emit an event to the parent and let the parent make the necessary changes. Otherwise, there is ambiguity in which component "owns" the property.
One Way Data Flow
All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around.
Sending Messages to Parents with Events
Can be off base here but I believe this happens because in vue component props are not reactive, so their objects are not being observed in depth. Or rather they are "a little bit reactive", reassigning the root prop does cause the DOM update but is not expected to be done manually and you'll see a warning when doing such on development build:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "..."
And for as why props are not completely reactive in the first place: https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow
To work around the whole issue you must pass any necessary props to the component data and if those props were passed as nested objects you might also want to completely avoid mutating them from within the component since it will propagate to the parent which, unless clearly mentioned, can be a source of bad news.

React - How can I wrap and element depending on a boolean parameter?

I'm using react-bootstrap tooltip to build a react component. According to react-boostrap specifications, I need to wrap my element with an OverlayTrigger element, like this:
<OverlayTrigger overlay={this.getTooltipElement()} placement='left'>
//element
</OverlayTrigger>
This works just fine, but my component requires to show the tooltip when hovered (usual behavior) AND only if a boolean variable is set to true. I've tried this:
if (booleanParameter) {
return (<OverlayTrigger overlay={this.getTooltipElement()} placement='left'>
{myElementVariable};
</OverlayTrigger>)
} else {
return myElementVariable;
}
But when the tooltip is instructed to show (by the boolean parameter), I get the following warning:
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the undefined component.
Important: getTooltipElement() uses component state fields.
... and the component starts to act erratically. How should I go to solve my problem? How can I wrap and element depending on a boolean parameter? Is there another, less elaborated solution?
I believe the approach you are using is fine, the warning essentially tells you that somewhere - possibly in whatever getTooltipElement() returns, you're calling setState after the component unmounted. You fix this by checking whether the component is still mounted before you set the state:
if(this.isMounted())
this.setState({...});
By the way, if you give your components a 'displayName' attribute, the warning will actually tell you in which component it happened, making it easier to find.

Categories