React Universal Interface for Component Patterns
React Universal Interface (react-universal-interface) is a lightweight utility library designed to simplify the creation of React components that can be consumed via multiple popular patterns, including Function-as-a-Child (FaCC), render props, component props, and Higher-Order Components (HOCs). It offers two primary functions: `render` for processing various child/prop definitions within a component's render method, and `createEnhancer` for generating HOCs. The package's current stable version is 0.6.2, released in May 2020. Given the lack of updates since then, the project appears to be abandoned, with no active release cadence. Its key differentiator was providing a unified API to handle diverse component interaction paradigms, a common challenge in the evolving React ecosystem before Hooks became the dominant approach for logic reuse.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'props')
cause Often occurs when `this` context is lost in a class component, or `render` is called outside a component's instance context.fixEnsure `render` is called within a class component's method (e.g., `this.render()`) and `this.props` is correctly accessible. Use arrow functions for event handlers to preserve `this`. -
TS2345: Argument of type '{ children: ({ counter }: { counter: number; }) => Element; }' is not assignable to parameter of type 'MyDataProps'.cause Incorrectly typing the component props when using TypeScript, not extending `UniversalProps` correctly, or passing unexpected children/props to the `MyData` component.fixEnsure your component's props interface extends `UniversalProps<TState>`, where `TState` is the type of data your component provides (e.g., `MyDataState` in the example). Verify that the data provided to children matches the expected type.
Warnings
- breaking `tslib` was moved from a direct dependency to a peerDependency in version 0.6.2. If you are upgrading from a version prior to 0.6.2, you might need to manually install `tslib` in your project if you encounter build errors related to missing TypeScript helper functions.
- gotcha This package appears to be abandoned, with the last release in May 2020. It is unlikely to receive updates for compatibility with newer React versions (e.g., React 17, 18, 19 and beyond) or address new issues. Functionality may break with future React updates.
- gotcha The patterns promoted (FaCC, render props, HOCs) are still valid but less commonly used for stateful logic sharing in modern React development, which largely favors Hooks. While this library unifies them, relying heavily on it might diverge from current best practices and introduce additional abstraction layers.
Install
-
npm install react-universal-interface -
yarn add react-universal-interface -
pnpm add react-universal-interface
Imports
- render
const { render } = require('react-universal-interface');import { render } from 'react-universal-interface'; - createEnhancer
const createEnhancer = require('react-universal-interface').createEnhancer;import { createEnhancer } from 'react-universal-interface'; - UniversalProps
import { UniversalProps } from 'react-universal-interface';
Quickstart
import React, { Component } from 'react';
import { render, createEnhancer, UniversalProps } from 'react-universal-interface';
interface MyDataState {
counter: number;
}
interface MyDataProps extends UniversalProps<MyDataState> {}
class MyData extends Component<MyDataProps, MyDataState> {
state = { counter: 0 };
componentDidMount() {
this.interval = setInterval(() => {
this.setState(prevState => ({ counter: prevState.counter + 1 }));
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
interval: NodeJS.Timeout | undefined;
render() {
return render(this.props, this.state);
}
}
const MyChildComponent: React.FC<MyDataState> = ({ counter }) => (
<div>Current counter: {counter}</div>
);
// Usage with Function-as-a-Child (FaCC)
function App() {
return (
<div>
<h2>FaCC Example:</h2>
<MyData>{(state) => <MyChildComponent {...state} />}</MyData>
<h2>Render Prop Example:</h2>
<MyData render={(state) => <MyChildComponent {...state} />} />
<h2>Component Prop Example:</h2>
<MyData comp={MyChildComponent} />
<MyData component={MyChildComponent} />
<h2>Prop Injection Example:</h2>
<MyData>
<MyChildComponent />
</MyData>
</div>
);
}
// Example of Higher Order Component usage
const withCounter = createEnhancer(MyData, 'data');
const EnhancedChild = withCounter(MyChildComponent);
function HOCApp() {
return (
<div>
<h2>HOC Example:</h2>
<EnhancedChild /> {/* MyChildComponent will receive 'data' prop from MyData */}
</div>
);
}
export default App;