React without Pain: Avoid Re-Renders and Simplify Dependencies
Tags: react, javascript, redux, mlyn
Published: 2024-05-13 11:22:14

Tracking re-renderings in React can be a painstaking process. Fine-grain reactivity pattern offers a solution that completely removes this problem, allowing React engineers to forget about tracking dependencies and focus on writing code. In this article, we’ll explore how library Mlyn simplifies dependency management and prevents unnecessary re-renders in React applications.

## Dependency Management: A Common Challenge

In traditional React applications, managing state and dependencies can often lead to complex and error-prone code. Let’s consider a simple counter example to illustrate this issue.

## Traditional React Example

```js
import React, { useState, useCallback } from "react";
const Counter = () => {
  const [count, setCount] = useState(0);
  const onIncrement = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, [count]); // Dependency on count
  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={onIncrement}>Increment</button>
    </div>
  );
};

export default Counter;
```

## Issue with Dependencies
In this example, the `onIncrement` function is wrapped in `useCallback` with count as a dependency. Every time `count` changes, `onIncrement` is re-created.

## Simplifying with Mlyn
Mlyn introduces fine-grain reactivity, allowing you to manage state updates without worrying about dependencies. Let’s rewrite the same example using Mlyn.

```js
import React, { useCallback } from "react";
import { rc, useSubject } from "mlyn/react";
const Counter = rc(() => {
  const state = useSubject({ count: 0 });
  const increment = useCallback(() => {
    state.count(state.count() + 1);
  }, []);
  return (
    <div>
      <h1>Count: {state.count()}</h1>
      <button onClick={onIncrement}>Increment</button>
    </div>
  );
});


export default Counter;
```

Since the reference of `state.count` never changes, we can read it in `useCallback` without re-creating a new function.

## 
Benefits of Fine-Grain Reactivity

- Stable Callbacks: The onIncrement function in Mlyn does not need `state.count` as a dependency. This stability prevents unnecessary re-creation of the function. And consumers of `onIncrement` will not re-render when `count` changes.
- Simplified Code: With Mlyn, you don’t need to track dependencies manually.

## Extracting IncrementButton: A Closer Look at Re-Rendering

Let’s extract the increment button into the `IncrementButton` component to understand how Mlyn’s approach prevents unnecessary re-renders.

## Traditional React: Re-Rendering Issue
In the traditional example, `IncrementButton` re-renders every time `count` changes because increment is a new function reference each time.

```js
const IncrementButton = React.memo(({ onIncrement }) => {
  console.log("IncrementButton re-rendered");
  return (
    <div>
      <button onClick={onIncrement}>Increment from Child</button>
    </div>
  );
});

const Counter = () => {
  const [count, setCount] = useState(0);
  const onIncrement = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, [count]); // Dependency on count
  return (
    <div>
      <h1>Count: {count}</h1>
      <IncrementButton onIncrement={onIncrement} />
    </div>
  );
};
```

## Mlyn: Preventing Unnecessary Re-Renders
With Mlyn, onIncrement remains the same reference, so IncrementButton does not re-render unnecessarily. This is a key advantage of fine-grain reactivity.

Example Revisited
```js
const Counter = rc(() => {
  const state = useSubject({ count: 0 });
  const onIncrement = useCallback(() => {
    state.count(state.count() + 1); // No dependencies needed
  }, []);
  return (
    <div>
      <h1>Count: {state.count()}</h1>
      <IncrementButton onIncrement={onIncrement} />
    </div>
  );
});
```

## Summary
Mlyn’s fine-grain reactivity simplifies state management by:

Eliminating the Need for Dependency Tracking: You can write cleaner, more maintainable code without worrying about manually updating dependencies.
Preventing Unnecessary Re-Renders: Components only re-render when their actual state or props change, improving performance and efficiency.
By adopting Mlyn, React engineers can focus on writing feature-rich code without the hassle of managing complex state dependencies. Try integrating Mlyn into your next project and experience the ease of fine-grain reactivity!

Interested in mlyn? [check it out on github](https://github.com/vaukalak/mlyn)