What Are "Reactive Values" in React?

In React, "reactive values" refer to values 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 values 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.

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 function 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.

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.

In contrast, the dependency array of the effect in the first example is empty because the effect's code block does not use any reactive value.

Similarly, 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.


Hope you found this post useful. It was published . Please show your love and support by sharing this post.