如果不是工作需要,对于 HOC 我是拒绝的,毕竟现在是 Hook 的时代了。之前还真不知道有 recompose 这种简化 HOC 的神器,我还是太孤露寡闻了。
Recompose is a React utility belt for function components and higher-order components.
就像作者说得那样这东西就是为了增强函数式组件和 HOC 的,所以说有了 Hook 还蛮鸡肋的,所以作者说不再维护这个东西了,手动狗头。
用得比较多得 API 好像就下面这两个 withState() 和 withHandlers()
withState()
下面这个的 ExpandButton 是我们平时 HOC 的写法,就是把 state 和 setState 的方法作为 props 传入来达到数据增强的手段,而 withState 的使用就直接省略了这一部分,直接传入三个参数来达到增强组件的效果
withState(
stateName: string, // the name we call our state
stateUpdaterName: string, // the name of the function to call
initialState: any | (props: Object) => any // optional default state to pass
): HigherOrderComponent
- stateName:到时要用到的 state
- stateUpdaterName:对应 stateName 的 setState
initialState:初始 state 的值
class ExpandButtonContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
expanded: false
};
this.setExpanded = this.setExpanded.bind(this);
}
setExpanded(expanded) {
this.setState({ expanded });
}
render() {
return (
<ExpandButton
expanded={this.state.expanded}
setExpanded={this.setExpanded} />
);
}
}
```javascript const enhanceWithExpandedState = withState(“expanded”, “setExpanded”, false);
const ExpandButton = enhanceWithExpandedState(({ expanded, setExpanded }) => (
通过代码可以清晰地看出 recompose 中帮我们做了一层封装,然后将我们传入的参数映射为对于的字段、方法
```javascript
import { createFactory, Component } from 'react'
import setDisplayName from './setDisplayName'
import wrapDisplayName from './wrapDisplayName'
const withState = (
stateName,
stateUpdaterName,
initialState
) => BaseComponent => {
const factory = createFactory(BaseComponent)
class WithState extends Component {
state = {
stateValue:
typeof initialState === 'function'
? initialState(this.props)
: initialState,
}
updateStateValue = (updateFn, callback) =>
this.setState(
({ stateValue }) => ({
stateValue:
typeof updateFn === 'function' ? updateFn(stateValue) : updateFn,
}),
callback
)
render() {
return factory({
...this.props,
[stateName]: this.state.stateValue,
[stateUpdaterName]: this.updateStateValue,
})
}
}
if (process.env.NODE_ENV !== 'production') {
return setDisplayName(wrapDisplayName(BaseComponent, 'withState'))(
WithState
)
}
return WithState
}
export default withState
withHandlers()
从上面的使用可以看出来,withState 中 关于 state 状态修改函数的设置还是过于简单,所以 recompose 提供了 withHandlers 允许你自定义更新 state 的函数,从而达到增强 withState 的效果
const enhancedState = Recompose.withState("count", "handleCounter", 0);
const enhancedHandler = Recompose.withHandlers({
incrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count + 1);
},
decrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count - 1);
}
});
const Counter = ({ count, incrementCounter, decrementCounter }) => (
<div>
<h1>{count}</h1>
<button onClick={incrementCounter}>Increment</button>
<button onClick={decrementCounter}>Decrement</button>
</div>
);
const App = enhancedState(enhancedHandler(Counter));
compose()
compose 一顿组合操作,代码的优雅程度直接飙升
const enhanced = Recompose.compose(
Recompose.withState("count", "handleCounter", 0),
Recompose.withHandlers({
incrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count + 1);
},
decrementCounter: props => event => {
event.preventDefault();
props.handleCounter(props.count - 1);
}
})
);
const App = enhanced(({ count, incrementCounter, decrementCounter }) => {
return (
<div>
<h1>{count}</h1>
<button onClick={incrementCounter}>Increment</button>
<button onClick={decrementCounter}>Decrement</button>
</div>
);
});
源代码的实现,也只是通过 reduce 和 柯里化的操作来实现组合而已
const compose = (...funcs) =>
funcs.reduce((a, b) => (...args) => a(b(...args)), arg => arg)
export default compose