5

@api property used to be read-only for the component that hosts it, but it's not the case today, we are able to assign values to api property.

Is this a bug?

Eg: Child comp:

@api apiProp

ConnectedCallback() {
   apiProp = "test"; // this line used to give error. But now it's not.
}

2 Answers 2

11

The LWC framework doesn't do anything to prevent public property reassignment. In other words, from within your component, you are allowed to set the value of properties marked with the @api decorator.

In general, it is a bad practice to override a public property from within a component as it goes against the unidirectional dataflow model. There are still valid use cases for component to reflect their internal component state change via a public property. A good example of this is a custom input component reflecting its internal value change to the value public property.

The @lwc/lwc/no-api-reassignments ESLint can help catching those issues. This rule is enabled by default with the @salesforce/eslint-config-lwc/recommended ESLint config.


That said, the LWC framework prevents mutation to objects passed as public property. If a component receives an object via public property, any property addition, update or delete on the object will result in an Invalid mutation error.

Note that this check is only enforced in dev/debug mode to avoid the performance overhead in production.


The following example showcases the difference between public property reassignment and object mutation.

import { api, LightningElement } from 'lwc';

export default class extends LightningElement {
    @api aString;
    @api anObject;

    connectedCallback() {
        this.aString = 'test'   // 👍 Valid
        this.anObject.test = 1  // 🛑 Invalid mutation: Cannot set "test" on "[object Object]". "[object Object]" is read-only.
    }
}
3

The documentation now makes no mention of restrictions on writing to @api properties, and also states:

Note

Reactivity changed significantly in the Lightning Web Components Open Source 1.1.0 release.

As far as I can tell, this is perfectly legal. I even wrote some code that compiles and runs according to this new behavior.

However, be aware that if the parent changes the value, it will be overridden.

I think this change was implemented to allow you to set a default value when you call a @wire or other asynchronous code, but still need to set a default value for the component.

To be certain, though, I'll doublecheck with some people. In the meantime, I don't recommend doing this if another option is available. Data should always flow from parent to child, so if you do this, you are potentially breaking assumptions.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .