CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-inferno

An extremely fast, React-like JavaScript library for building modern user interfaces

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

refs.mddocs/

Refs and Forward Refs

Reference system for accessing DOM elements and component instances, with forward ref support for passing refs through component boundaries.

Capabilities

Create Ref

Creates a ref object for accessing DOM elements or component instances.

/**
 * Creates a ref object for accessing DOM elements or component instances
 * @returns RefObject with current property initially set to null
 */
function createRef<T = Element>(): RefObject<T>;

interface RefObject<T> {
  readonly current: T | null;
}

Usage Examples:

import { createRef, Component, createVNode, VNodeFlags } from "inferno";

class TextInputComponent extends Component {
  constructor(props) {
    super(props);
    this.inputRef = createRef<HTMLInputElement>();
  }

  focusInput = () => {
    if (this.inputRef.current) {
      this.inputRef.current.focus();
    }
  };

  componentDidMount() {
    // Access DOM element after mount
    if (this.inputRef.current) {
      console.log('Input element:', this.inputRef.current);
    }
  }

  render() {
    return createVNode(VNodeFlags.HtmlElement, 'div', null, [
      createVNode(VNodeFlags.InputElement, 'input', null, null, ChildFlags.HasInvalidChildren, {
        ref: this.inputRef,
        type: 'text',
        placeholder: 'Enter text'
      }),
      createVNode(VNodeFlags.HtmlElement, 'button', null, 'Focus Input', ChildFlags.HasInvalidChildren, {
        onClick: this.focusInput
      })
    ]);
  }
}

Forward Ref

Creates a component that forwards refs to child components or DOM elements.

/**
 * Creates a component that forwards refs to child components or DOM elements
 * @param render - Render function that receives props and ref
 * @returns Component that can accept and forward refs
 */
function forwardRef<T = any, P = Props<any>>(
  render: (
    props: Readonly<{ children?: InfernoNode }> & Readonly<P>,
    ref: RefObject<T>
  ) => InfernoNode
): any;

Usage Examples:

import { forwardRef, createRef, createVNode, VNodeFlags } from "inferno";

// Forward ref component for custom input
const CustomInput = forwardRef<HTMLInputElement, { placeholder?: string }>((props, ref) => {
  return createVNode(VNodeFlags.InputElement, 'input', 'custom-input', null, ChildFlags.HasInvalidChildren, {
    ref: ref,
    type: 'text',
    placeholder: props.placeholder
  });
});

class ParentComponent extends Component {
  constructor(props) {
    super(props);
    this.customInputRef = createRef<HTMLInputElement>();
  }

  handleClick = () => {
    if (this.customInputRef.current) {
      this.customInputRef.current.focus();
      this.customInputRef.current.value = 'Focused!';
    }
  };

  render() {
    return createVNode(VNodeFlags.HtmlElement, 'div', null, [
      createComponentVNode(VNodeFlags.ForwardRefComponent, CustomInput, {
        ref: this.customInputRef,
        placeholder: 'Custom input'
      }),
      createVNode(VNodeFlags.HtmlElement, 'button', null, 'Focus Custom Input', ChildFlags.HasInvalidChildren, {
        onClick: this.handleClick
      })
    ]);
  }
}

Mount Ref

Internal function for mounting refs (used by the rendering system).

/**
 * Internal function for mounting refs during the rendering process
 * @param ref - Ref callback or RefObject
 * @param value - Value to assign to the ref
 * @param lifecycle - Array of lifecycle functions to execute
 */
function mountRef(ref: any, value: any, lifecycle: Array<() => void>): void;

Unmount Ref

Internal function for unmounting refs (used by the rendering system).

/**
 * Internal function for unmounting refs during component cleanup
 * @param ref - Ref callback or RefObject to unmount
 */
function unmountRef(ref: any): void;

Ref Types

Ref Callback

type Ref<T = Element> = {
  bivarianceHack(instance: T | null): any;
}['bivarianceHack'];

Forward Ref Interface

interface ForwardRef<P, T> extends Inferno.StatelessComponent<P> {
  ref: Ref<T>;
}

Ref Usage Patterns

DOM Element Access

class ScrollableComponent extends Component {
  constructor(props) {
    super(props);
    this.containerRef = createRef<HTMLDivElement>();
  }

  scrollToTop = () => {
    if (this.containerRef.current) {
      this.containerRef.current.scrollTop = 0;
    }
  };

  scrollToBottom = () => {
    if (this.containerRef.current) {
      this.containerRef.current.scrollTop = this.containerRef.current.scrollHeight;
    }
  };

  render() {
    return createVNode(VNodeFlags.HtmlElement, 'div', null, [
      createVNode(VNodeFlags.HtmlElement, 'div', 'scrollable', this.props.children, ChildFlags.UnknownChildren, {
        ref: this.containerRef,
        style: { height: '200px', overflow: 'auto' }
      }),
      createVNode(VNodeFlags.HtmlElement, 'button', null, 'Scroll to Top', ChildFlags.HasInvalidChildren, {
        onClick: this.scrollToTop
      }),
      createVNode(VNodeFlags.HtmlElement, 'button', null, 'Scroll to Bottom', ChildFlags.HasInvalidChildren, {
        onClick: this.scrollToBottom
      })
    ]);
  }
}

Component Instance Access

class ChildComponent extends Component {
  getValue() {
    return this.state.value;
  }

  reset() {
    this.setState({ value: '' });
  }

  render() {
    return createVNode(VNodeFlags.InputElement, 'input', null, null, ChildFlags.HasInvalidChildren, {
      value: this.state.value,
      onChange: (e) => this.setState({ value: e.target.value })
    });
  }
}

class ParentComponent extends Component {
  constructor(props) {
    super(props);
    this.childRef = createRef<ChildComponent>();
  }

  handleGetValue = () => {
    if (this.childRef.current) {
      console.log('Child value:', this.childRef.current.getValue());
    }
  };

  handleReset = () => {
    if (this.childRef.current) {
      this.childRef.current.reset();
    }
  };

  render() {
    return createVNode(VNodeFlags.HtmlElement, 'div', null, [
      createComponentVNode(VNodeFlags.ComponentClass, ChildComponent, {
        ref: this.childRef
      }),
      createVNode(VNodeFlags.HtmlElement, 'button', null, 'Get Value', ChildFlags.HasInvalidChildren, {
        onClick: this.handleGetValue
      }),
      createVNode(VNodeFlags.HtmlElement, 'button', null, 'Reset', ChildFlags.HasInvalidChildren, {
        onClick: this.handleReset
      })
    ]);
  }
}

Callback Refs

class CallbackRefComponent extends Component {
  setInputRef = (element: HTMLInputElement | null) => {
    this.inputElement = element;
    if (element) {
      console.log('Input element mounted:', element);
    } else {
      console.log('Input element unmounted');
    }
  };

  focusInput = () => {
    if (this.inputElement) {
      this.inputElement.focus();
    }
  };

  render() {
    return createVNode(VNodeFlags.HtmlElement, 'div', null, [
      createVNode(VNodeFlags.InputElement, 'input', null, null, ChildFlags.HasInvalidChildren, {
        ref: this.setInputRef,
        type: 'text'
      }),
      createVNode(VNodeFlags.HtmlElement, 'button', null, 'Focus', ChildFlags.HasInvalidChildren, {
        onClick: this.focusInput
      })
    ]);
  }
}

Multiple Refs

class MultiRefComponent extends Component {
  constructor(props) {
    super(props);
    this.refs = {
      input1: createRef<HTMLInputElement>(),
      input2: createRef<HTMLInputElement>(),
      container: createRef<HTMLDivElement>()
    };
  }

  focusFirst = () => {
    this.refs.input1.current?.focus();
  };

  focusSecond = () => {
    this.refs.input2.current?.focus();
  };

  getAllValues = () => {
    const values = {
      input1: this.refs.input1.current?.value || '',
      input2: this.refs.input2.current?.value || ''
    };
    console.log('All values:', values);
    return values;
  };

  render() {
    return createVNode(VNodeFlags.HtmlElement, 'div', null, [
      createVNode(VNodeFlags.HtmlElement, 'div', 'input-container', [
        createVNode(VNodeFlags.InputElement, 'input', null, null, ChildFlags.HasInvalidChildren, {
          ref: this.refs.input1,
          placeholder: 'Input 1'
        }),
        createVNode(VNodeFlags.InputElement, 'input', null, null, ChildFlags.HasInvalidChildren, {
          ref: this.refs.input2,
          placeholder: 'Input 2'
        })
      ], ChildFlags.HasNonKeyedChildren, {
        ref: this.refs.container
      }),
      createVNode(VNodeFlags.HtmlElement, 'div', null, [
        createVNode(VNodeFlags.HtmlElement, 'button', null, 'Focus First', ChildFlags.HasInvalidChildren, {
          onClick: this.focusFirst
        }),
        createVNode(VNodeFlags.HtmlElement, 'button', null, 'Focus Second', ChildFlags.HasInvalidChildren, {
          onClick: this.focusSecond
        }),
        createVNode(VNodeFlags.HtmlElement, 'button', null, 'Get Values', ChildFlags.HasInvalidChildren, {
          onClick: this.getAllValues
        })
      ], ChildFlags.HasNonKeyedChildren)
    ]);
  }
}

Forward Ref Patterns

HOC with Forward Ref

function withLogging<P>(WrappedComponent: any) {
  return forwardRef<any, P>((props, ref) => {
    console.log('Rendering with props:', props);
    
    return createComponentVNode(
      VNodeFlags.ComponentClass,
      WrappedComponent,
      { ...props, ref }
    );
  });
}

const LoggedInput = withLogging(CustomInput);

Composite Components

const InputGroup = forwardRef<HTMLInputElement, { label: string; placeholder?: string }>((props, ref) => {
  return createVNode(VNodeFlags.HtmlElement, 'div', 'input-group', [
    createVNode(VNodeFlags.HtmlElement, 'label', null, props.label),
    createVNode(VNodeFlags.InputElement, 'input', null, null, ChildFlags.HasInvalidChildren, {
      ref: ref,
      placeholder: props.placeholder
    })
  ]);
});

Best Practices

  1. Use createRef() for object refs: More predictable than callback refs
  2. Check ref.current before use: Always verify the ref is not null
  3. Don't overuse refs: Prefer props and state for data flow
  4. Forward refs in reusable components: Allow parent components to access underlying elements
  5. Avoid string refs: Use object refs or callback refs instead
  6. Clean up in unmount: Remove event listeners attached via refs

docs

component-system.md

core-rendering.md

event-handling.md

fragments-utilities.md

index.md

refs.md

vnode-creation.md

tile.json