Hoist Non-React Statics
hoist-non-react-statics is a focused utility library for React applications designed to copy non-React specific static properties from a child component to a parent component. It functions similarly to `Object.assign` but intelligently blacklists React's internal static keywords to prevent unintentional overrides. This mechanism is critical for Higher-Order Components (HOCs) to correctly preserve static methods, `propTypes`, `defaultProps`, or other custom static properties from the wrapped component, preventing their loss during composition. The current stable version is 3.3.2. The package maintains a stable release cadence primarily driven by React's evolution (e.g., ForwardRefs support) and TypeScript definition enhancements, ensuring broad compatibility across various React versions. Its key differentiator is its precise targeting of user-defined static properties while respecting React's internals, solving a common HOC pattern challenge documented by React itself.
Common errors
-
TypeError: Object doesn't support this property or method
cause This error in IE8 typically indicates a problem with `Object.defineProperty`.fixInstall and include a comprehensive polyfill for `Object.defineProperty` to fix its broken implementation in IE8. -
Warning: Function components cannot be given refs. Attempts to access this ref will fail.
cause This warning (or similar `ref` issues) often occurs when using an HOC that wraps a `ForwardRef` component with `hoist-non-react-statics` versions older than 3.x.fixUpgrade `hoist-non-react-statics` to version 3.x or higher to gain proper `ForwardRef` support. -
MyComponent.someStaticMethod is not a function
cause A static method or property defined on your wrapped component is not accessible via the HOC, suggesting it wasn't hoisted.fixEnsure you are calling `hoistNonReactStatics` correctly after defining your HOC. If on `v2.x` or later, verify the static property is enumerable. If using a third parameter to `hoistNonReactStatics`, ensure the static method is not accidentally excluded.
Warnings
- breaking Starting with v2.0.0, the library only hoists enumerable static properties. If your components relied on non-enumerable static properties being hoisted, this change will break that behavior.
- breaking Versions prior to 3.x do not support React's `ForwardRef` feature. HOCs using older versions will lose `ref` functionality when wrapping `ForwardRef` components.
- gotcha The package utilizes `Object.defineProperty`, which has a known broken implementation in Internet Explorer 8 (IE8). Running the library in IE8 without a proper polyfill will lead to runtime errors.
- gotcha The third parameter allows explicit exclusion of statics. Accidentally excluding a required static will lead to missing functionality on the wrapped component.
Install
-
npm install hoist-non-react-statics -
yarn add hoist-non-react-statics -
pnpm add hoist-non-react-statics
Imports
- hoistNonReactStatics
const hoistNonReactStatics = require('hoist-non-react-statics');import hoistNonReactStatics from 'hoist-non-react-statics';
- hoistNonReactStatics (CommonJS)
const hoistNonReactStatics = require('hoist-non-react-statics'); - hoistNonReactStatics (TypeScript types)
import hoistNonReactStatics, { NonReactStatics } from 'hoist-non-react-statics';
Quickstart
import hoistNonReactStatics from 'hoist-non-react-statics';
import React from 'react';
// Imagine a HOC that wraps a component
function withLogger(WrappedComponent) {
class Logger extends React.Component {
static displayName = `WithLogger(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
render() {
console.log(`Rendering ${WrappedComponent.displayName || WrappedComponent.name}`);
return <WrappedComponent {...this.props} />;
}
}
// Crucially, hoist non-React statics from WrappedComponent to Logger
// This ensures statics like propTypes, defaultProps, or custom static methods are preserved.
return hoistNonReactStatics(Logger, WrappedComponent);
}
// Example usage:
class MyComponent extends React.Component {
static someStaticMethod() {
return 'Hello from static!';
}
render() {
return <div>My Component Content</div>;
}
}
const EnhancedComponent = withLogger(MyComponent);
console.log(EnhancedComponent.someStaticMethod()); // Should output 'Hello from static!'