Type safe and Zero-cost React library to work with higher-order component (HOC)
Install with npm
npm install react-with-hoc
Or install with yarn
yarn add react-with-hoc
import { withDefault, withOverride, withHocs } from "react-with-hoc";
export const Hello = (() => {
function Hello({ name }: { name: string }) {
return <div>Hello {name}!</div>;
}
return withHocs([withDefault({ name: "World" })])(Hello);
})();
// <Hello /> is equivalent to <div>Hello World!</div>
// <Hello name="You" /> is equivalent to <div>Hello You!</div>
export const HelloYou = withOverride("name", "You")(Hello);
// <HelloYou /> is equivalent to <div>Hello You!</div>
// <HelloYou name="..." /> is a typescript error ❌
Lets suppose you have the following code and then you need a query inside your App component
const queryClient = new QueryClient();
function App() {
// Oops... ❌
// This is an error because App is not wrapped by QueryClientProvider
const query = useQuery({...});
return (
<QueryClientProvider client={queryClient}>
<>...</>
</QueryClientProvider>
);
}
export default App;
Using react-with-hoc
, you can easily fix this with:
import {withWrapper, withOverride} from "react-with-hoc";
const queryClient = new QueryClient();
function App() {
// ✅
const query = useQuery({...});
return (
<>...</>
);
}
export default withWrapper(
withOverride({ client: queryClient })(QueryClientProvider)
)(App);
// for didactic purpose, the following code could also be applied
// const MyQueryClientProvider = withOverride({ client: queryClient })(QueryClientProvider)
// export default withWrapper(MyQueryClientProvider)(App);
Using IIFE
import { withWrapper, withOverride, withHocs } from "react-with-hoc";
const queryClient = new QueryClient();
const App = (() => {
function App() {
// ✅
const query = useQuery({...});
return <>...</>;
}
return withHocs([
withWrapper(withOverride({ client: queryClient })(QueryClientProvider)),
])(App);
})();
export default App;
Check out an entire project with react-with-hoc, see the demo and try to imagine creating a reusable component with the same flexibility
Take a look on how simple it's the final result
const RedHour = withOverride("color", "red")(HourPointer);
const Square = withStyle({
borderRadius: 0,
})(ClockCircle);
function App(): JSX.Element {
return (
<>
<div>
<h1>The default clock</h1>
<Clock />
</div>
<div>
<h1>#1 Variant: without minute marks</h1>
<Clock MinuteMarks={null} />
</div>
<div>
<h1>#2 With a red hour pointer</h1>
<Clock HourPointer={(): typeof RedHour => RedHour} />
</div>
<div>
<h1>#3 Inside a square</h1>
<Clock Circle={(): typeof Square => Square} />
</div>
</>
);
}