In React, "reactive values" refer to the values declared directly inside the component body that:
- Participate in the React data flow, and;
- Can trigger a re-render of the component when their value changes.
These values include props, state, and any other variables and functions that are used in the component's rendering logic. Values derived from other reactive values are also reactive. These values can change on a re-render and be recalculated during subsequent renders if they are updated.
Reactive values are tracked by React for changes. When any of these values change, React schedules a re-render of the component so that it can update the output to reflect the new values. For this reason, it's crucial (for hooks that support dependency array) to include all reactive values the hook depends on, in its dependency array. Otherwise, the callback of the hook may not execute when expected.
When using the useEffect()
hook for example, you need to specify which reactive values the effect depends on by passing them as an array of dependencies. If any of these dependencies change, the effect will be executed again. If no dependencies are specified, the effect will only be executed once when the component is mounted.
For example, in the following code you can see that the values that are outside the component are not reactive, while those that are inside the component body are reactive:
const serverUrl = 'https://localhost:1234'; // not reactive const category = 'general'; // not reactive function Products() { const [products, setProducts] = useState([]); // reactive useEffect(() => { (async () { const fetchedProducts = await fetchProducts(serverUrl, category); setProducts(fetchedProducts); })(); }, []); // no dependency on reactive values }
In this example, both "serverUrl
" and "category
" are not reactive because they never change due to a re-render. They're both always the same no matter how many times the component re-renders. Also, as you may have noticed, the dependency array of the effect is empty. That's because the effect's code block does not use any reactive value.
Compare this to the following example where the non-reactive values (from the previous example) are moved inside the component's function body:
function Products({ category }) { // reactive const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // reactive const [products, setProducts] = useState([]); // reactive useEffect(() => { (async () { const fetchedProducts = await fetchProducts(serverUrl, category); setProducts(fetchedProducts); })(); }, [category, serverUrl]); // reactive values added to deps array }
In this example, "serverUrl
" and "category
" are reactive values, because they are either passed as a prop or declared as a state inside the component, and they affect the component's rendering logic. Therefore, they must be included in the dependency array of the useEffect()
hook as the effect depends on these reactive values. The reason for this is that any reactive value can change on a re-render, and when that happens the effect needs to re-synchronize based on the changed values.
If you move the variables "serverUrl
" and "category
" inside the effect, they won't need to be passed to the effect's dependency array because they aren't calculated during rendering, and are not reactive:
function Products() { const [products, setProducts] = useState([]); // reactive useEffect(() => { (async () { const serverUrl = 'https://localhost:1234'; // not reactive const category = 'general'; // not reactive const fetchedProducts = await fetchProducts(serverUrl, category); setProducts(fetchedProducts); })(); }, []); // no dependency on reactive values }
Please note that it's important to include all reactive values that the effect depends on in the dependency array, or else the effect may not execute when expected.
This post was published (and was last revised ) by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.