What is "Lane" in React?
Tags: react, javascript
Published: 2021-07-15 00:49:54

A concept called "Lane" is used inside React.

[Initial Lanes implementation by acdlite · Pull Request #18796 · facebook/react](https://github.com/facebook/react/pull/18796)

React 18 alpha was recently released, and many of the concurrent features are based on the Lane.

Lane is a 32-bit representation of a task at reconcile time, and the actual code for Lane is as follows;

```jsx
// https://github.com/facebook/react/blob/9212d994ba939f20a04220a61e9776b488381596/packages/react-reconciler/src/ReactFiberLane.new.js
const NoLane: Lane = 0b0000000000000000000000000000000;
const SyncLane: Lane = 0b0000000000000000000000000000001
const TransitionLanes: Lanes = 0b0000000001111111111111111000000;
const IdleLane: Lanes = 0b0100000000000000000000000000000;
const OffscreenLane: Lane = 0b1000000000000000000000000000000;
```

As you can see, lanes exist for each type of task, with the exception of NoLane (when there is no task), but basically lanes with higher priority are represented by smaller numbers.

By using 32 bits, bitmask can be used to manipulate lanes. For example, if multiple lanes are bitmasked into one lane, there is no need to compare all lanes relative to each other, which simplifies implementation and saves memory.

Let's take a look at the actual function that performs bitmasking.

```jsx
export function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
  return a | b;
}
```

This function, as the name suggests, merges lanes and returns them. For example, it can be used as follows.

```jsx
mergeLanes(
  NoLane /*0b0000000000000000000000000000000*/,
  OffscreenLane /*0b1000000000000000000000000000000*/
)

// => 0b1000000000000000000000000000000
```

In the above example, a Lane with no tasks (NoLane) is updated to an OffscreenLane. Since Lanes are attached to Fiber, we can update the Lane of the target Fiber as follows.

```jsx
fiber.lanes = mergeLanes(
  fiber.lanes /* NoLane */, 
  OffscreenLane
)
// => OffscreenLane
```

Let's take another look at the function `isSubsetOfLanes`.

```jsx
export function isSubsetOfLanes(set: Lanes, subset: Lanes) {
  return (set & subset) === subset;
}
```

This function returns whether or not the result of the AND operation of Lane matches the subset. It is not clear what makes it useful, so I will try to write some more specific patterns.

```jsx
isSubsetOfLanes(
  NonIdleLanes, /*0b0001111111111111111111111111111*/
  SyncLane /*0b0000000000000000000000000000001*/
)
// => true. SyncLane is not Idle task

isSubsetOfLanes(
  NonIdleLanes, /*0b0001111111111111111111111111111*/
  OffscreenLane /*0b1000000000000000000000000000000*/
)
// => false. OffscreenLane is Idle task

isSubsetOfLanes(
  TransitionLanes, /*0b0000000001111111111111111000000*/
  TransitionLane1 /*0b0000000000000000000000001000000*/
)
// => true. TransitionLane1 is included in TransitionLanes
```

As mentioned above, `isSubsetOfLanes` allows you to determine if the corresponding Lane is a subset of the target Fiber. 

For example, there is a function `scheduleWorkOnParentPath`. This function, roughly speaking, is responsible for notifying the upper level parent that the lower level child has a task.

```jsx
// https://github.com/facebook/react/blob/a8964649bb6332cf1f8d723f81ce97cc5a1886ff/packages/react-reconciler/src/ReactFiberNewContext.new.js#L142
export function scheduleWorkOnParentPath(
  parent: Fiber | null,
  renderLanes: Lanes,
) {
  // Update the child lanes of all the ancestors, including the alternates.
  let node = parent;
  while (node !== null) {
    const alternate = node.alternate;
    if (!isSubsetOfLanes(node.childLanes, renderLanes)) {
      node.childLanes = mergeLanes(node.childLanes, renderLanes);
      if (alternate !== null) {
        alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);
      }
    } else if (
      alternate !== null &&
      !isSubsetOfLanes(alternate.childLanes, renderLanes)
    ) {
      alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);
    } else {
      // Neither alternate was updated, which means the rest of the
      // ancestor path already has sufficient priority.
      break;
    }
    node = node.return;
  }
}
```

Here, `node.return` is the Fiber of a parent or multiple parents, so you can see that it is a function that updates childLanes by following the path of the parent in order. For example, it can be used to tell the parent when the React.Context is updated in children.

In this function, `isSubsetOfLanes` is used.

```jsx
    if (!isSubsetOfLanes(node.childLanes, renderLanes)) {
      node.childLanes = mergeLanes(node.childLanes, renderLanes);
      if (alternate !== null) {
        alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);
      }
    } else if (
```

Since node represents parent here, we can see that we are doing something like this: "If parent.childLanes (`node.childLanes` in the code) is not a subset of the target Lane, update parent.childLanes to the value merged with the target Lane." By doing this, we can move the lanes of children to the parent side. As a result, if you look at fiber.childrenLanes at reconcile time, you will know that the lower layer needs to be re-rendered.

In this way, Lanes make it easy to group multiple tasks together and still determine their priority in a few passes; when reconciliation, we can just refer to / update / merge Lanes and focus on the main algorithm. As a result, an architecture that matches the idea of Fiber and Suspense can be realized.

In addition to Lane, there are several other core PR that will be implemented in React 18 alpha, which are detailed in the following thread.

[https://twitter.com/rickhanlonii/status/1402771549808214016](https://twitter.com/rickhanlonii/status/1402771549808214016)

[https://twitter.com/dan_abramov/status/1402927593406582787](https://twitter.com/dan_abramov/status/1402927593406582787)

[https://twitter.com/acdlite/status/1402982843962343425](https://twitter.com/acdlite/status/1402982843962343425)

Isn't it amazing to think that after all the design, implementation, verification, and design iterations, a major version upgrade has finally been made since Fiber was announced?