
Lightning Web Components have quite a lot going on behind the scenes. One of the newer changes is the introduction of reactive properties. Reactive properties are variables you declare in components that fire page rerenders when changed. These variables can be specific to a single component, or they can be passed into children components, which creates a framework for sophisticated app design.
Reactive properties have changed since LWC’s inception, so this post will cover the new developments!
Natively Reactive Properties
Let’s start with a simple example to show LWC reactivity. I’m making a component that displays a user input on a page:
LWC Javascript
import { LightningElement } from 'lwc';
export default class Reactive extends LightningElement {
reactiveText = '';
assign(e){
this.reactiveText = e.target.value;
}
}
LWC HTML
<template>
<div>
<input type="text" name="ReactivePropertyValue" onkeyup={assign}/>
<br/>
{reactiveText}
</div>
</template>
This is as simple as it gets. This component has a single input, ReactivePropertyValue, whose value gets assigned to the reactive property ‘reactiveText.’ reactiveText is displayed under the input:

When you type a value into this input field, it will display under in and update in real time! This is reactivity in action!

This may seem simple, but this is what makes sophisticated web apps. Any primitive data type declared in a Lightning Web Component is reactive. But, what is happening behind the scenes? Salesforce is rerendering the entire template when a reactive property changes. This also fires any renderedCallback() methods. renderedCallback() is a lifecycle hook that fires after the page as been rendered. It can be used to make some really fancy apps.
To demonstrate what is happening, if I add a renderedCallback() to my component that does a console log everytime it is fired:
renderedCallback(){
console.log('I rendered');
}

The component initially fired a renderedCallback when it finished loading and then one event everytime I typed, updating the value of the reactive property reactiveText. Use this to your advantage.
Declaring Reactive Properties
Primitive data types are reactive by default, but arrays and objects are not. I’ll adjust my component to use an object:
LWC Javascript
import { LightningElement} from 'lwc';
export default class Reactive extends LightningElement {
reactiveText = {text1:'', text2:''};
renderedCallback(){
console.log('I rendered');
}
assign(e){
this.reactiveText.text1 = e.target.value;
}
}
LWC HTML
<template>
<div>
<input type="text" name="ReactivePropertyValue" onkeyup={assign}/>
<br/>
{reactiveText.text1}
</div>
</template>

In this case, the object did not rerender even though we are targeting a key-value pair inside it. To get an object (and array or list) to also be reactive, tag it with the ‘@track’ property. Make sure to import ‘track’ from ‘lwc’:
import { LightningElement, track } from 'lwc';
export default class Reactive extends LightningElement {
@track reactiveText = {text1:'', text2:''};
renderedCallback(){
console.log('I rendered');
}
assign(e){
this.reactiveText.text1 = e.target.value;
}
}

Cross-Component Reactive Properties
With Lightning Web Components, you can pass property values from parent to child. Properties that are configured this way have the reactive decorator ‘@api.’ This also means they follow the same reactive behavior as natively reactive or ‘@track’ decorated properties.
Say we pass in the value of reactiveText.text1 to another component that renders it, instead of rendering it in our component:
reactive LWC
<template>
<div>
<input type="text" name="ReactivePropertyValue" onkeyup={assign}/>
<br/>
<c-reactive-display display-text={reactiveText.text1}></c-reactive-display>
</div>
</template>
import { LightningElement, track } from 'lwc';
export default class Reactive extends LightningElement {
@track reactiveText = {text1:'', text2:''};
renderedCallback(){
console.log('I rendered');
}
assign(e){
this.reactiveText.text1 = e.target.value;
}
}
reactiveDisplay LWC
<template>
<div>
{displayText}
</div>
</template>
import { LightningElement, api } from 'lwc';
export default class ReactiveDisplay extends LightningElement {
@api displayText = '';
renderedCallback(){
console.log('Child component rendered');
}
}
Now, reactive is simply an input that sets the value for reactiveText.text1. reactiveDisplay is a child component of reactive that displays the value of displayText. displayText is tagged with the ‘@api’ decorator and it is assigned the value of reactiveText1.text1 in reactive’s HTML.
What happens when you start typing?

reactiveDisplay displays the text! I added a renderedCallback() in both components so you can also see that the renderedCallback(), and thus the rerendering behavior, or each component.