Security News
Maven Central Adds Sigstore Signature Validation
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.
react-hoc-pipe
Advanced tools
Chain, setup and reuse Higher-Order Components easily accross your React application.
On a React project, you often use the same HOC, with sometimes the same arguments. pipe()
enable to create a pipe of HOC, and reuse it accross your application.
A predefined HOC pipe, named pipeRequest
, is also provided. You can create your own pipe, or use pipeRequest and extends it with your HOCs.
Do you want to see a concrete example now? See HOC pipe request or a full reusable HOC pipe
npm install react-hoc-pipe --save
or with yarn
yarn add react-hoc-pipe
pipe()
is a reusable pipe of HOC.
const hocs = {
myFirstHOC: { ... }
mySecondHOC: { ... }
}
const myPipe = () => pipe(hocs)
Then, reuse it !
class Component extends React.Component {
...
}
const App = myPipe()
.myFirstHOC(params)
.mySecondHOC()
.render(Component)
...
render() {
return <App />
}
const hocs = {
withData: {
externalsParams: [],
HOC: externalsParams => data => App => {
return class Request extends React.Component {
render() {
return <App {...this.props} {...data} />
}
}
},
},
}
externalsParams
- optional - functions to set parameters that will be used inside HOC. More detail
data
- optional - yours HOC arguments
App
- React Component
Full example:
const hocs = {
withData: {
externalsParams: [],
HOC: (externalsParams) => (data) => App => {
return class Request extends React.Component {
render() {
return <App {...this.props} {...data} />
}
}
},
}
}
const myPipe = () => pipe(hocs)
...
const App = myPipe()
.withData({ foo: 'bar' })
.render((props) => {
return <div>{props.foo}</dib>
})
I know, this example is completely useless. But it's simple. You can then build your complex HOC.
externalsParams
?externalsParams
are functions to set parameters that will be used inside HOC. It's usefull because you can set paramters before or after the HOC call in the pipe.
const hocs = {
withData: {
externalsParams: ['addData']
HOC: (externalsParams) => (data) => App => {
return class Request extends React.Component {
render() {
// addData[0] correspond to the first argument of addData()
const externalsData = externalsParams.addData[0];
return <App {...this.props} {...data} {...externalsData} />
}
}
},
}
}
const myPipe = () => pipe(hocs)
...
const App = myPipe()
.withData({ foo: 'bar' })
.addData({ foo2: 'bar2' })
.render((props) => {
return <div>{props.foo} {props.foo2}</dib>
})
"Wait, why do not simply use only withData()
and pass all data through it" :question:
Good question ! And the anwser is simple: sometimes, you want to reuse a pipe, with the same parameter 95% of the time, and 5% remaining, you want to override it.
Example:
const hocs = {
request: {
externalsParams: ['renderLoader'],
HOC: ...,
}
}
const Loader = () => <div>...</div>
const myPipe = () => pipe(hocs).renderLoader(Loader)
...
const Page1 = myPipe()
.request(...)
.render(...)
...
const Page2 = myPipe()
.request(...)
.render(...)
You defined your spinner only once, and it will be use into all of your myPipe()
, until you override it. If you want to override it for a specific component, it's simple:
const Page1 = myPipe()
.request(..)
.renderLoader(() => <div>Loading...</div>)
.render(...)
:warning: externals params doesn't care about the call order. Externals parameters can be call before or after his HOC. Both Page1
and Page2
are equivalent:
const Page1 = myPipe()
.request()
.renderLoader()
.render()
const Page2 = myPipe()
.renderLoader()
.request()
.render()
However, the call order of HOC is important !
Page1
and Page2
are not the same:
const Page1 = myPipe()
.connect(...)
.request(...)
.render(Component)
const Page2 = myPipe()
.request()
.connect()
.render(Component)
The classique HOC syntax correspond to this:
const Page1 = connect(...)(request(...)(Component))
const Page2 = request(...)(connect(...)(Component))
Do you want a full real usefull example ? Well. I made a HOC pipe focus on the request handling.
pipeRequest()
is a predefined HOC pipe, focus on the request feature. It makes it possible to perform a request, show a loader, map request results to props, and then render your component,
import React from 'react'
import { pipeRequest } from 'react-hoc-pipe'
class MyComponent extends React.Component {
...
}
const App = pipeRequest()
.request((props) => fetch('http://website.com/posts'))
.mapRequestToProps((response) => ({ posts: response.posts }))
.renderLoader(() => <div>Loading...</div>)
.render(MyComponent)
Just below, the documentation of pipeRequest()
import { pipeRequest } from 'react-hoc-pipe'
/**
* hocs are optional
*/
const hocs = {
...
}
const App = pipeRequest(hocs)
/**
* async request. Must return a Promise
*
* optional
*/
.request(props => fetch('...'))
/**
* map the request results to props
*
* By default, request results are not sent as props to the render()
* Because sometime, you doesn't want to get the results directly.
* It's the case if you use redux actions with dispatch. You perform a request,
* but don't want to get the result from the Promise
*
* optional
*/
.mapRequestToProps(response => ({
foo: response.bar,
}))
/**
* Functionnal component or class component
*
* It's render during the request process
* If there is no renderLoader, final render is use
*
* optional
*/
.renderLoader(() => <div>is Loading...</div>)
/**
* Functionnal component or class component
* Final render
*
* required
*/
.render(Component)
Here, I will use pipeRequest()
, but if you doesn't need request handling, you can use pipe()
import { pipeRequest } from 'react-hoc-pipe'
import { connect } from 'react-redux'
const hocs = {
connect: {
HOC: (externalsParams) => (mapStateToProps, mapDispatchToProps) => App => {
return connect(mapStateToProps, mapDispatchToProps)(App);
},
// Or the simpler and shorter version
HOC: (externalsParams) => connect
}
}
const App = pipeRequest({ connect })
.connect(
mapStateToProps,
mapDispatchToProps,
)
.request(...)
.mapRequestProps(...)
.renderLoader(...)
.render(props => <div>...</div>)
If you use externals HOC without argument, like withRouter()
, the syntaxe is a bit different than HOC with arguments, like connect()
.
connect: connect(params)(App)
withRouter: withRouter(App)
As you can see, connect()
take params and return another function, while withRouter()
directly take the React component as parameter. So the externals HOC config is a bit different.
Note: in the following examples, externalsParams
are useless.
import { pipeRequest } from 'react-hoc-pipe'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
const hocs = {
connect: {
HOC: (externalsParams) => connect
}
withRouter: {
HOC: (externalsParams) => () => withRouter
}
}
const App = pipeRequest(hocs)
.connect(
mapStateToProps,
mapDispatchToProps,
)
.request(props => fetch('...'))
.withRouter()
.render(props => <div>...</div>)
externals params can be usefull for defined mapDispatchToProps
, if you often use the same actions.
import { pipeRequest } from 'react-hoc-pipe'
import { connect } from 'react-redux'
import { fetchUser } from 'src/store/actions'
const hocs = {
connect: {
externalsParams: ['mapDispatchToProps']
HOC: (externalsParams) => (mapStateToProps, mapDispatchToProps) => {
const finalMapDispatchToProps = externalsParams.mapDispatchToProps || mapDispatchToProps
return connect(mapStateToProps, finalMapDispatchToProps)
}
}
}
const myPipeRequest = () => pipeRequest(hocs).mapDispatchToProps({ fetchUser })
...
const App = myPipeRequest()
.connect(mapStateToProps)
.request(props => props.fetchUser()) // fetchUser is binded to redux store
.render(props => <div>...</div>)
import { pipeRequest } from 'react-hoc-pipe'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import { fetchUser } from 'src/store/actions'
const hocs = {
connect: {
HOC: () => connect,
},
withRouter: {
HOC: () => () => withRouter,
},
}
const pipeWithUser = externalsHOCs =>
pipeRequest({ hocs, ...externalsHOCs })
.withRouter()
.connect(
(state, props) => {
const userId = props.match.params.userId
return {
userId,
user: state.users[userId],
}
},
{ fetchUser },
)
.request(props => props.fetchUser(userId))
.renderLoader(() => <div>Fetching user...</div>)
Then, reuse it !
const UserView = (props) => (
<div>
<div>{props.user.firstName}</div>
<div>{props.user.lastName}</div>
</div>
)
const User = pipeWithUser().render(UserView)
...
class Page extends React.Component {
render() {
return (
<div>
<User />
</div>
)
}
}
FAQs
React HOC Pipe
We found that react-hoc-pipe demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.
Security News
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
Research
Security News
Socket researchers uncovered a backdoored typosquat of BoltDB in the Go ecosystem, exploiting Go Module Proxy caching to persist undetected for years.