如果不是工作需要,对于 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 statestateUpdaterName: string, // the name of the function to callinitialState: 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 (<ExpandButtonexpanded={this.state.expanded}setExpanded={this.setExpanded} />);}}
```javascript const enhanceWithExpandedState = withState(“expanded”, “setExpanded”, false);
const ExpandButton = enhanceWithExpandedState(({ expanded, setExpanded }) => (
通过代码可以清晰地看出 recompose 中帮我们做了一层封装,然后将我们传入的参数映射为对于的字段、方法```javascriptimport { 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
