facebook/reactMITd083ec1Report / request removal

Refs & Forwarding

Refs provide an imperative handle to a rendered value, such as a class instance or a host node. createRef creates the object that stores that handle in its current field.

forwardRef is the explicit mechanism that lets a function receive a ref and pass it to something it renders. The reconciler separately detects ref changes and schedules ref work, but the supplied reconciler excerpt does not show the code that performs the final attachment.

Sources: packages/react/src/ReactCreateRef.js:12-20, packages/react/src/ReactForwardRef.js:12-83, packages/react-reconciler/src/ReactFiberBeginWork.js:1409-1427

Core concepts

Ref object

A ref object is a mutable object whose current field starts as null; in development, React seals the object before returning it.

export function createRef(): RefObject {
  const refObject = {
    current: null,
  };
  if (__DEV__) {
    Object.seal(refObject);
  }
  return refObject;
}

The important contract is that callers retain the returned object and React can later update its current value. The shown implementation establishes the storage shape and initial value, but not the later assignment site.

Sources: packages/react/src/ReactCreateRef.js:12-20, packages/react/src/ReactCreateRef.js:12-19

Forward-ref element type

A forward-ref element type is the object returned by forwardRef, containing the special $$typeof marker and the supplied render function.

The render function is typed to receive two parameters: props and ref; its result is a React$Node.

Sources: packages/react/src/ReactForwardRef.js:12-83, packages/react/src/ReactForwardRef.js:12-17

Ref effect

A ref effect is scheduled when a ref is removed, added, or changed on a fiber. The reconciler represents that pending work with the Ref and RefStatic flags.

Sources: packages/react-reconciler/src/ReactFiberBeginWork.js:1409-1427

How createRef provides a target

Calling createRef allocates a fresh object rather than returning an existing shared container. Its current property is initially null, so a caller can distinguish an unassigned ref from one that has received a rendered value.

In development builds, Object.seal prevents the ref object’s shape from being changed after creation. The excerpt does not state whether this affects updates to current; it only shows that sealing occurs before the object is returned.

The ref can ultimately point at a class instance in the demonstrated forwarding test: a Child class is rendered through a wrapper, and the test expects ref.current instanceof Child after rendering completes.

A forwarded ref can also remain null when the render function returns null. Both the single-child and multiple-child tests assert that the ref stays null in that case.

Sources: packages/react/src/ReactCreateRef.js:12-20, packages/react/src/ReactCreateRef.js:12-19, packages/react/src/tests/forwardRef-test.internal.js:49-70, packages/react/src/tests/forwardRef-test.js:53-77

How forwardRef changes function-component input

Without forwarding, the shown forwardRef API does not describe a normal function component receiving a second ref argument. Instead, it constructs a special element type whose render function is explicitly called with props and ref.

The test demonstrates the data movement: the outer RefForwardingComponent receives ref, passes it as forwardedRef to Wrapper, and Wrapper places that value on the rendered Child as ref.

const RefForwardingComponent = React.forwardRef((props, ref) => (
  <Wrapper {...props} forwardedRef={ref} />
));

const ref = React.createRef();

ReactNoop.render(<RefForwardingComponent ref={ref} value={123} />);

The key change is therefore not that every function component gains ref behavior; it is that forwardRef creates a distinct element type carrying a render function with an explicit ref parameter.

The supplied code does not include the ordinary function-component ref error or rejection path, so the precise internal reason that a normal function component cannot take a ref by default is not proven here. What is proven is that React provides a separate REACT_FORWARD_REF_TYPE representation for the supported forwarding case.

Sources: packages/react/src/ReactForwardRef.js:12-17, packages/react/src/ReactForwardRef.js:51-54, packages/react/src/tests/forwardRef-test.internal.js:57-69

Validation around the render function

In development, forwardRef warns if it receives a memo component instead of a render function, or if the supplied value is not a function.

It also warns when the render function has a parameter count other than zero or two, and when the render function has defaultProps.

In development, assigning displayName to the returned element type can also assign a name to an anonymous inner render function when that function has no existing name or display name.

Sources: packages/react/src/ReactForwardRef.js:18-29, packages/react/src/ReactForwardRef.js:31-47, packages/react/src/ReactForwardRef.js:55-79

How the reconciler schedules ref work

During begin work, markRef reads workInProgress.ref and compares it with the current fiber’s ref. If the new ref is null but the current ref is not, it schedules ref work.

If the new ref is non-null, markRef accepts a function or object ref, and it throws for other values. It then schedules ref work when the fiber is mounting or when the ref identity differs from the current fiber’s ref.

This means ref processing is change-sensitive: an unchanged ref does not receive a newly scheduled Ref effect through this function, while mounting, replacement, and removal do.

The direct answer to “before or after commit?” is limited by the supplied evidence. The shown code schedules a Ref effect during begin work, but it does not show the later commit-phase function that writes a host node or class instance into the ref. Therefore, this excerpt alone cannot prove whether the actual attachment occurs before or after any particular commit sub-phase.

Sources: packages/react-reconciler/src/ReactFiberBeginWork.js:1409-1416, packages/react-reconciler/src/ReactFiberBeginWork.js:1417-1427, packages/react-reconciler/src/ReactFiberBeginWork.js:1411-1427, packages/react-reconciler/src/ReactFiberBeginWork.js:1409-1427

How it connects

The public construction APIs belong with Public API Reference, which documents the exported surface containing createRef and forwardRef. The element-type distinction belongs with Element Types & Components, because forwardRef returns a special element type rather than a plain render function.

The ref comparison uses fiber state such as current, workInProgress, and workInProgress.ref; the surrounding data structure is explained by Fiber Architecture.

The pending Ref effect must eventually be interpreted by the synchronous mutation and effect machinery described in Commit Phase, but that execution is not included in this context pack.

For browser nodes, the renderer-specific host operations belong with ReactDOM Host Config. The supplied DOM excerpt shows insertion into a parent node, but it does not show ref assignment.

Sources: packages/react/src/ReactCreateRef.js:12-20, packages/react/src/ReactForwardRef.js:12-83, packages/react-reconciler/src/ReactFiberBeginWork.js:1409-1427, packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js:1156-1173

Key takeaways

  • createRef returns a sealed-in-development object with current: null.
  • forwardRef creates a special element type whose render function receives props and ref.
  • Forwarding lets a function-shaped render path pass its ref to a class or host target.
  • markRef schedules ref work when a ref is mounted, removed, or changed.
  • The supplied excerpts do not show the final ref attachment point, so they cannot establish its exact commit timing.

Sources: packages/react/src/ReactCreateRef.js:12-20, packages/react/src/ReactForwardRef.js:12-83, packages/react/src/tests/forwardRef-test.internal.js:57-70, packages/react-reconciler/src/ReactFiberBeginWork.js:1409-1427

Want this for your repos?

Try Angada AI Wiki