Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
React Web Project Building. Part 2 — HOCs
In previous part we created AppKernel HOC (higher-order component) to add some useful features for your app.
In this part we will continue work with HOCs and functional programming. We will split our big HOC into some small parts which you can reuse to build your own app HOC with only useful parts.
But before we start, we need to remember some functional programming basics.
HOC (higher-order component) is a kind of higher-order function. It’s a function which has component as an argument and it returns a new component.
In this part we will use functional composition and some kind of curry.
Let’s remember our AppKernel from the pervious part:
import React, { StrictMode, Suspense } from 'react';import { ErrorBoundary, FallbackView,} from 'react-error-boundaries';import { Provider } from 'react-redux';import { BrowserRouter as Router } from 'react-router-dom';import store from '../store';const AppKernel = (Component) => {return () => (<StrictMode> <ErrorBoundary FallbackComponent={FallbackView}> <Provider store={store}> <Router> <Suspense fallback={<div>Loading...</div>}> <Component /> </Suspense> </Router> </Provider> </ErrorBoundary> </StrictMode> );};export default AppKernel;
And just imagine our goal:
import { compose } from './helpers';import strictMode from './hocs/strictMode';import errorBoundary from './hocs/errorBoundary';import redux from './hocs/redux';import router from './hocs/router';import suspense from './hocs/suspense';const AppKernel = compose( strictMode, errorBoundary, redux, router, suspense,);export default AppKernel;
It looks more declarative — less code with the same functionality. And other benefit — you can compose any part in the HOC and reuse it in any other React app.
Who wants to see all code now, I created a github repository.
So, let’s start form the beginning.
First of all, we need to create compose function. For this I created a helper inside of our src/app directory. I didn’t created own compose function because we use redux, it has own compose function and it works perfect for us.
import { compose } from 'redux';
The main idea is making small HOCs for each layer. For this I created a wrapper:
const wrapper = (WrapperComponent, wrapperProps = {}, Component) => () => ( <WrapperComponent {...wrapperProps}> <Component /> </WrapperComponent>);
It gets WrapperComponent like StrictMode or Suspense and wraps the Component. We can add any property if we need it, for example if we need to pass store in Redux Provider:
<Provider store={store}>
But to use it in composition we need to curry this function:
const hocCreator = (WrapperComponent, wrapperProps, Component) => {if (!WrapperComponent) {throw new Error('WrapperComponent should be set!'); }return Component ? wrapper(WrapperComponent, wrapperProps, Component) : Cmp => {if (!Cmp) {throw new Error('Component should be set!'); }return wrapper(WrapperComponent, wrapperProps, Cmp); }};
It’s uses wrapper function with some checking: if we didn’t put the Component it returns another function.
And all code of our helper:
import React from 'react';import { compose } from 'redux';const wrapper = (WrapperComponent, wrapperProps = {}, Component) => () => ( <WrapperComponent {...wrapperProps}> <Component /> </WrapperComponent>);const hocCreator = (WrapperComponent, wrapperProps, Component) => {if (!WrapperComponent) {throw new Error('WrapperComponent should be set!'); }return Component ? wrapper(WrapperComponent, wrapperProps, Component) : Cmp => {if (!Cmp) {throw new Error('Component should be set!'); }return wrapper(WrapperComponent, wrapperProps, Cmp); }};export { hocCreator, compose,};
Now we are ready to create a HOC for each layer.
StrictMode
src/app/hocs/strictMode.js:
import { StrictMode } from 'react';import { hocCreator } from '../helpers';export default hocCreator(StrictMode);
It’s too easy. We create a HOC from the React StrictMode component using our hocCreator helper function.
If we imagine how it works we get something like this:
() => ( <StrictMode> <Component /> </StrictMode>)
ErrorBoundary
src/app/hocs/errorBoundary.js:
import { ErrorBoundary, FallbackView } from 'react-error-boundaries';import { hocCreator } from '../helpers';export default hocCreator(ErrorBoundary, { FallbackComponent: FallbackView });
Here we can see how I use properties for ErrorBoundary component.
It works like this:
() => ( <ErrorBoundary FallbackComponent={FallbackView}> <Component /> </ErrorBoundary>)
Redux
src/app/hocs/redux.js:
import { Provider } from 'react-redux';import { hocCreator } from '../helpers';import store from '../../store';export default hocCreator(Provider, { store });
Router
src/app/hocs/router.js:
import { BrowserRouter } from 'react-router-dom';import { hocCreator } from '../helpers';export default hocCreator(BrowserRouter);
Suspense
src/app/hocs/suspense.js:
import React, { Suspense } from 'react';import { hocCreator } from '../helpers';export default hocCreator(Suspense, { fallback: <div>Loading...</div> });
And small bonus. I updated our page component to use only pure components. Pure components use the same idea like pure functions — no side effects.
It’s function with props arguments and it returns JSX:
props => JSX
src/page/index.js:
import React from 'react';import logo from '../logo.svg';import './index.css';const PageComponent = () => ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/page/index.js</code> and save to reload. </p> <aclassName="App-link"href="https://reactjs.org"target="_blank"rel="noopener noreferrer" > Learn React </a> </header> </div>);export default PageComponent;
That’s all.
Now you can easily create any HOC using hocCreator helper and create your own AppKernel with any useful features for your app.
React Web Project Building. Part 2 — HOCs was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.