如果不是工作需要,对于 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 的使用就直接省略了这一部分,直接传入三个参数来达到增强组件的效果

  1. withState(
  2. stateName: string, // the name we call our state
  3. stateUpdaterName: string, // the name of the function to call
  4. initialState: any | (props: Object) => any // optional default state to pass
  5. ): HigherOrderComponent
  • stateName:到时要用到的 state
  • stateUpdaterName:对应 stateName 的 setState
  • initialState:初始 state 的值

    1. class ExpandButtonContainer extends React.Component {
    2. constructor(props) {
    3. super(props);
    4. this.state = {
    5. expanded: false
    6. };
    7. this.setExpanded = this.setExpanded.bind(this);
    8. }
    9. setExpanded(expanded) {
    10. this.setState({ expanded });
    11. }
    12. render() {
    13. return (
    14. <ExpandButton
    15. expanded={this.state.expanded}
    16. setExpanded={this.setExpanded} />
    17. );
    18. }
    19. }

    ```javascript const enhanceWithExpandedState = withState(“expanded”, “setExpanded”, false);

const ExpandButton = enhanceWithExpandedState(({ expanded, setExpanded }) => (

setExpanded(!expanded)}> { expanded ?
:
}
));

  1. 通过代码可以清晰地看出 recompose 中帮我们做了一层封装,然后将我们传入的参数映射为对于的字段、方法
  2. ```javascript
  3. import { createFactory, Component } from 'react'
  4. import setDisplayName from './setDisplayName'
  5. import wrapDisplayName from './wrapDisplayName'
  6. const withState = (
  7. stateName,
  8. stateUpdaterName,
  9. initialState
  10. ) => BaseComponent => {
  11. const factory = createFactory(BaseComponent)
  12. class WithState extends Component {
  13. state = {
  14. stateValue:
  15. typeof initialState === 'function'
  16. ? initialState(this.props)
  17. : initialState,
  18. }
  19. updateStateValue = (updateFn, callback) =>
  20. this.setState(
  21. ({ stateValue }) => ({
  22. stateValue:
  23. typeof updateFn === 'function' ? updateFn(stateValue) : updateFn,
  24. }),
  25. callback
  26. )
  27. render() {
  28. return factory({
  29. ...this.props,
  30. [stateName]: this.state.stateValue,
  31. [stateUpdaterName]: this.updateStateValue,
  32. })
  33. }
  34. }
  35. if (process.env.NODE_ENV !== 'production') {
  36. return setDisplayName(wrapDisplayName(BaseComponent, 'withState'))(
  37. WithState
  38. )
  39. }
  40. return WithState
  41. }
  42. export default withState

withHandlers()

从上面的使用可以看出来,withState 中 关于 state 状态修改函数的设置还是过于简单,所以 recompose 提供了 withHandlers 允许你自定义更新 state 的函数,从而达到增强 withState 的效果

  1. const enhancedState = Recompose.withState("count", "handleCounter", 0);
  2. const enhancedHandler = Recompose.withHandlers({
  3. incrementCounter: props => event => {
  4. event.preventDefault();
  5. props.handleCounter(props.count + 1);
  6. },
  7. decrementCounter: props => event => {
  8. event.preventDefault();
  9. props.handleCounter(props.count - 1);
  10. }
  11. });
  12. const Counter = ({ count, incrementCounter, decrementCounter }) => (
  13. <div>
  14. <h1>{count}</h1>
  15. <button onClick={incrementCounter}>Increment</button>
  16. <button onClick={decrementCounter}>Decrement</button>
  17. </div>
  18. );
  19. const App = enhancedState(enhancedHandler(Counter));

compose()

compose 一顿组合操作,代码的优雅程度直接飙升

  1. const enhanced = Recompose.compose(
  2. Recompose.withState("count", "handleCounter", 0),
  3. Recompose.withHandlers({
  4. incrementCounter: props => event => {
  5. event.preventDefault();
  6. props.handleCounter(props.count + 1);
  7. },
  8. decrementCounter: props => event => {
  9. event.preventDefault();
  10. props.handleCounter(props.count - 1);
  11. }
  12. })
  13. );
  14. const App = enhanced(({ count, incrementCounter, decrementCounter }) => {
  15. return (
  16. <div>
  17. <h1>{count}</h1>
  18. <button onClick={incrementCounter}>Increment</button>
  19. <button onClick={decrementCounter}>Decrement</button>
  20. </div>
  21. );
  22. });

源代码的实现,也只是通过 reduce 和 柯里化的操作来实现组合而已

  1. const compose = (...funcs) =>
  2. funcs.reduce((a, b) => (...args) => a(b(...args)), arg => arg)
  3. export default compose

参考资料

  1. How to use recompose withState to add state to functional components
  2. Using Recompose to Share Functionality Between React Components