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:
- Values generated by
useState()
. - Values generated by
useReducer()
. - Props of a component.
Anything not listed here is non-reactive, so updating it will not cause the component to re-render.
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.