Capítulo 78 de 116

Chapter 78: cloneElement

Core Idea

cloneElement(element, props?, children?) creates a copy of an existing React element with some props overridden or added — a legacy escape hatch the docs steer away from, in favor of explicit render props or composition via children/named element props.

Key Concepts

  • Signature: cloneElement(element, newProps, newChildren?) — returns a new element with element's original props shallow-merged with newProps (new values override existing ones), optionally replacing children too.
  • Historical use case: letting a parent inject extra props into a child element it didn't create (received as children or another prop) — e.g. a Tabs component cloning each tab child to inject an isSelected prop, without the caller needing to pass it manually.
  • Why the docs discourage it: cloning makes data flow implicit and fragile — the child element's actual rendered props depend on both what the original caller wrote and an invisible parent-side mutation, making the component harder to reason about and type. It also doesn't work with function components that don't forward arbitrary extra props predictably.
  • Preferred alternatives: render props (passing a function as a prop that the parent calls with the data the child needs), or explicit composition (accepting specific named props/children slots) — both keep the actual data flow visible in the calling code rather than hidden inside a clone.

Code Examples

// Legacy pattern (discouraged):
const clonedChild = cloneElement(child, { isSelected: true });

// Preferred: explicit prop passed directly by the composing code
<Tab isSelected={index === activeIndex}>{child}</Tab>
  • What it demonstrates: the difference between implicitly injecting a prop via cloning vs. explicitly passing it where the composition actually happens.

Key Takeaways

  1. Treat cloneElement as a legacy pattern — reach for render props or explicit prop-passing/composition in new code.
  2. Cloning makes a component's actual runtime props partly invisible at the call site, which complicates debugging and TypeScript inference.
  3. It still exists and works for maintaining older codebases, but isn't the docs' recommended pattern for new component APIs.

Connects To

  • Ch 15 (Passing Props to a Component): the explicit-prop-passing pattern favored as the alternative.
  • Ch 77 (Children): another children-manipulation utility with a similar "consider the explicit alternative first" framing.