DEV Community

loading...

What is "Lane" in React?

okmttdhr
.
Updated on ・3 min read

A concept called "Lane" is used inside React.

Initial Lanes implementation by acdlite · Pull Request #18796 · facebook/react

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;

// 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;
Enter fullscreen mode Exit fullscreen mode

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.

export function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
  return a | b;
}
Enter fullscreen mode Exit fullscreen mode

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

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

// => 0b1000000000000000000000000000000
Enter fullscreen mode Exit fullscreen mode

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.

fiber.lanes = mergeLanes(
  fiber.lanes /* NoLane */, 
  OffscreenLane
)
// => OffscreenLane
Enter fullscreen mode Exit fullscreen mode

Let's take another look at the function isSubsetOfLanes.

export function isSubsetOfLanes(set: Lanes, subset: Lanes) {
  return (set & subset) === subset;
}
Enter fullscreen mode Exit fullscreen mode

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.

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
Enter fullscreen mode Exit fullscreen mode

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.

// 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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

    if (!isSubsetOfLanes(node.childLanes, renderLanes)) {
      node.childLanes = mergeLanes(node.childLanes, renderLanes);
      if (alternate !== null) {
        alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);
      }
    } else if (
Enter fullscreen mode Exit fullscreen mode

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/dan_abramov/status/1402927593406582787

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?

Discussion (2)

Collapse
suprabhasupi profile image
Suprabha

This is amazing, I wasn't aware of this.
Thanks a lot for information 😍

Collapse
lukeshiru profile image
LUKESHIRU

Wow, this was extremely interesting! Thanks a lot for taking the time to put this together. Love to see articles like this covering the internals of popular libraries like React <3