Skip to main content

Reactive Values

What Are Reactive Values?

Reactive values refers to anything that will cause the component to re-render after a change has been made, including:

Anything not listed here is non-reactive, so updating it will not cause the component to re-render.

caution

What about the values generated by createContext()? Aren't they reactive as well when we inject them into a component via useContext()?

Yes, but that only happens when context value and the function used to update the context value are generated using either useState() or useReducer(). If you put a non-reactive value in a context, updating it will not cause the component to re-render.

At the moment, reactive values in React are still coming from useState(), useReducer(), or the props of a component.

What Does Render Mean?

In React, "render" means to run the code in your component from top to bottom, and transform JSX elements into DOM nodes. Any subsequent render after the very first render is called re-render.

Examples

Reactive Values

import { useState } from 'react'

export const Example = () => {
const [count, setCount] = useState(0)

const increment = () => {
setCount(count + 1)
console.log(count)
}

return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
</div>
)
}

In this example, everytime the "Increment" button is clicked, the value of count will be incremented by 1. Since count is a reactive value, the component will re-render after it changes, thus "refreshing" the screen with the latest values.

However, you may have noticed that the value displayed in the console is always different from the value displayed on the screen. Good news is, this is not a bug, but it does confuse everyone! We'll explain this when we get to Component Rendering, just don't worry about it now.

Also, it's okay if you have no idea what does useState() do. Just keep in mind that changing reactive values will cause the component to re-render and you're good to go!

Non-reactive Values

import { useState } from 'react'

let count = 0

export const Example = () => {
const increment = () => {
count++
console.log(count)
}

return (
<div>
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
</div>
</div>
)
}

In this example, everytime the "Increment" button is clicked, the value of count will be incremented by 1. However, since count is a not-reactive value, updating it will not cause the component to re-render, no matter how many times count changes.

But be careful, this does not mean the changes of a non-reactive value will never be reflected on the screen! Let's take a look at the following example:

import { useState } from 'react'

let age = 0

export const Example = () => {
const [count, setCount] = useState(0)

const incrementCount = () => {
setCount(count + 1)
}

const incrementAge = () => {
age++
}

return (
<div>
<div>
<h1>Count: {count}</h1>
<button onClick={incrementCount}>Increment Count</button>
</div>
<div>
<h1>Age: {age}</h1>
<button onClick={incrementAge}>Increment Age</button>
</div>
</div>
)
}

In this example, count is a reactive value, while age is a non-reactive value. Thus:

  • Clicking "Increment Count" will update the value of count, and the component will re-render.
  • Clicking "Increment Age" will update the value of age, but the component will not re-render.

This is why in the above video, nothing seemed to happen when we clicked "Increment Age" for three times, but the screen suddenly went from Age: 0 to Age: 3 after "Increment Count" is clicked, which is confusing.

When to Make a Variable Reactive

To avoid the problem we see above, we have to be careful when declaring variables. A simple rule of thumb would be:

  • Make it a reactive when the value will change, and users must be informed of this change on the screen.
  • Otherwise just make it a non-reactive.