Hoist Non React Statics is a utility library for React higher-order components (HOCs) that safely copies non-React-specific static properties from a source component to a target component. It maintains React's static property blacklist to prevent overriding critical React internals while allowing the transfer of custom static methods and properties.
npm install hoist-non-react-staticsimport hoistNonReactStatics from 'hoist-non-react-statics';For CommonJS:
const hoistNonReactStatics = require('hoist-non-react-statics');import hoistNonReactStatics from 'hoist-non-react-statics';
import React from 'react';
// Source component with static properties
class MyComponent extends React.Component {
static customMethod() {
return 'custom';
}
static customProperty = 'value';
render() {
return <div>Hello World</div>;
}
}
// Higher-order component
function withEnhancement(WrappedComponent) {
class Enhancement extends React.Component {
render() {
return <WrappedComponent {...this.props} enhanced={true} />;
}
}
// Hoist statics from the wrapped component
return hoistNonReactStatics(Enhancement, WrappedComponent);
}
const EnhancedComponent = withEnhancement(MyComponent);
// EnhancedComponent now has the static properties from MyComponent
console.log(EnhancedComponent.customMethod()); // 'custom'
console.log(EnhancedComponent.customProperty); // 'value'The main utility function that copies non-React-specific static properties from a source component to a target component.
/**
* Copies non-react specific statics from a child component to a parent component
* @param {object} targetComponent - The component to copy statics to
* @param {object|string} sourceComponent - The component to copy statics from
* @param {object} [blacklist] - Object with keys to exclude from hoisting
* @returns {object} The targetComponent with hoisted static properties
*/
function hoistNonReactStatics(targetComponent, sourceComponent, blacklist);Usage Examples:
Basic hoisting:
import hoistNonReactStatics from 'hoist-non-react-statics';
const Enhanced = hoistNonReactStatics(targetComponent, sourceComponent);With blacklist to exclude specific statics:
hoistNonReactStatics(targetComponent, sourceComponent, {
myStatic: true,
myOtherStatic: true
});Key Behaviors:
childContextTypescontextTypecontextTypesdefaultPropsdisplayNamegetDefaultPropsgetDerivedStateFromErrorgetDerivedStateFromPropsmixinspropTypestypenamelengthprototypecallercalleeargumentsarityObject.prototypeReact Version Compatibility:
Browser Compatibility:
Object.definePropertyObject.definePropertyParameters:
targetComponentsourceComponentblacklistReturn Value: Returns the
targetComponentCommon Use Cases:
Examples with Different Component Types:
Class components:
class Button extends React.Component {
static variant = 'primary';
static getDisplayText() { return 'Button'; }
render() { return <button>{this.props.children}</button>; }
}
function withLogging(Component) {
class LoggedComponent extends React.Component {
componentDidMount() { console.log('mounted'); }
render() { return <Component {...this.props} />; }
}
return hoistNonReactStatics(LoggedComponent, Component);
}
const LoggedButton = withLogging(Button);
// LoggedButton.variant === 'primary'
// LoggedButton.getDisplayText() === 'Button'ForwardRef components:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="fancy" {...props} />
));
FancyButton.displayName = 'FancyButton';
FancyButton.customProp = 'custom';
function withWrapper(Component) {
const Wrapped = React.forwardRef((props, ref) => (
<div className="wrapper">
<Component ref={ref} {...props} />
</div>
));
return hoistNonReactStatics(Wrapped, Component);
}
const WrappedFancyButton = withWrapper(FancyButton);
// WrappedFancyButton.customProp === 'custom'
// WrappedFancyButton.displayName remains as set on Wrapped componentMemo components:
const MemoButton = React.memo(props => <button {...props} />);
MemoButton.customStatic = 'value';
function enhance(Component) {
function Enhanced(props) {
return <Component {...props} enhanced={true} />;
}
return hoistNonReactStatics(Enhanced, Component);
}
const EnhancedMemoButton = enhance(MemoButton);
// EnhancedMemoButton.customStatic === 'value'Inheritance chain example:
class BaseComponent extends React.Component {
static baseMethod() { return 'base'; }
static baseProp = 'base';
}
class ExtendedComponent extends BaseComponent {
static extendedMethod() { return 'extended'; }
static extendedProp = 'extended';
// Instance methods are not hoisted
instanceMethod() { return 'instance'; }
}
function withLogging(Component) {
class LoggedComponent extends React.Component {
componentDidMount() { console.log('Component mounted'); }
render() { return <Component {...this.props} />; }
}
return hoistNonReactStatics(LoggedComponent, Component);
}
const LoggedExtended = withLogging(ExtendedComponent);
// LoggedExtended.baseMethod() === 'base' (from prototype chain)
// LoggedExtended.baseProp === 'base' (from prototype chain)
// LoggedExtended.extendedMethod() === 'extended' (direct property)
// LoggedExtended.extendedProp === 'extended' (direct property)
// LoggedExtended.instanceMethod === undefined (instance methods not hoisted)