初探 Recompose

ohh_發表於2020-01-12

基本

Recompose是一個React實用庫,用於函式元件和高階元件。把它想象成React的lodash。它提供了很多 HOC 的效能優化方案,能幫助你以函式和可測的方式抽取資料獲取邏輯,HOC 組合和進行 props 操作。使你的程式碼清晰明瞭、易於閱讀維護和測試。

介紹幾個相關概念

函式元件

函式式元件,有時也被稱為無狀態元件。本質上就是一個常規的函式,接收一個 props 並返回一個元素。

  • 特點:
  1. 無生命週期方法;
  2. 只能訪問輸入的props,同樣的props會得到同樣的渲染結果,不會有副作用;
  3. 沒有this個ref。
高階元件

高階元件是一種接收元件為引數並返回一個新的元件的函式。(我們可以將函式式元件封裝進高階元件以解決狀態處理和渲染優化這樣的問題)

使用方法

下面簡單介紹一下compose、pure、onlyUpdateForKeys、withState、withHandlers、withStateHandlers、withProps等方法的使用。更多API可檢視官方文件

  • pure:效果與React.PureComponent相同
  • shouldUpdate: 接收一個函式,和shouldComponentUpdate內容一致,具體參考程式碼
  • onlyUpdateForKeys:如果指定的 props key 改變了才做更新
interface IProps {
  name: string
  title: string
  content: string
}
export const Base: SFC<IProps> = ({ name, title, content }) => {
  const time = new Date
  return (
    <p>
        <span>時間{time.getTime()}  </span>
        <span>姓名{name}  </span>
        <span>標題{title}  </span>
        <span>內容{content}  </span>
    </p>
  )
}

// 將SFC元件變成PureComponent元件

export const PureBaseComponent = pure(Base)

// 僅在 title發生變化的時候重新渲染元件

export const OnlyUpdateForKeysComponent = onlyUpdateForKeys(['title'])(Base)

// 接收一個方法 和生命週期中的和shouldComponentUpdate一致
// 返回一個布林值控制是否重新渲染。

const checkPropsChange = (props:IProps, nextProps:IProps) =>
    (nextProps.name !== props.name
  && nextProps.title === '渲染')
export const ShouldUpdateComponent = shouldUpdate(checkPropsChange)(Base)


// 這些方法都是通過shouldComponentUpdate來控制元件的重渲
// 不用寫類元件,比較簡單,推薦使用。
複製程式碼
  • compose:可以組合多個高階元件, 由下至上的組合;
  • withState: 因為函式式元件中沒有state,所以recompose提供了withState來滿足。接收三個引數,stateName: state的名稱;stateUpdaterName: 改變state的函式; initialState: 初始值。
  • withHandlers:和withState一起使用可以改變state的值。
interface IPropsBaseTwo extends IProps {
  onClick: () => void
  changeTitle: () => void
  changeContent: () => void
}

// 基礎元件都差不多一致

export const BaseTwo: SFC<IPropsBaseTwo> = ({ name, title, content, onClick,
  changeTitle, changeContent }) => {
  const time = new Date
  return (
    <p>
        <span>時間{time.getTime()}  </span>
        <button onClick={onClick}>姓名{name}  </button>
        <button onClick={changeTitle}>標題{title}  </button>
        <button onClick={changeContent}>內容{content}  </button>
    </p>
  )
}
//  compose 將多個高階元件組合起來,避免自己寫層層套用, 推薦!

// withState 傳入state名字,改變的方法名,初始值。
//單個的時候推薦這個用法,多個時推薦下面一種使用方式,請接著往下看

// withHandlers 可傳入多個方法, 
// 對應元件中的props的方法。返回一個高階函式接收withState裡面的方法名。 

export const WithStateComponent = compose(
  pure,
  withState('name', 'changeName', 'zhangsan'),
  withState('title', 'changeTitle', 'buzhidao'),
  withState('content', 'changeContent', '...'),
  withHandlers({
    onClick: ({changeName}) => () => {
      changeName('changeName')
    },
    changeTitle: ({changeTitle}) => () => {
      changeTitle('changeTitle')
    },
    changeContent: ({changeContent}) => () => {
      changeContent('changeContent')
    }
  })
)(BaseTwo)

複製程式碼
  • withStateHandlers:其實就相當於上面兩個方法的合集
  • lifecycle: 可以整合生命週期
const initialState = {
  name: 'zhangsan',
  title: 'buzhidao',
  content: '...'
}


// withStateHandlers 接受一個初始化state物件
// 第二個引數依舊是 對個方法的物件, 返回一個高階函式可接收state的值。

const withStateHandlersCom  = withStateHandlers(initialState, {
  onClick: ({name}) => () => {
    return {name: 'xxxxx', title: '啦啦啦', content:'contentxxxdff'}
  }
})

export const WithStateHandlersComponent = compose(
  pure,
  withStateHandlersCom,
  lifecycle({
    componentDidMount() {
      this.setState({ name: 'lifecycle' })
    }
  }))(BaseTwo)
複製程式碼
  • withProps/mapProps:相似,將新的props合併的原來的props;
沒有貼程式碼,更多方法可自行學習~
複製程式碼

總結

  1. 它們有助於防止濫用setState,而用props作為替代。
  2. 鼓勵 「smart」 和 「dumb」 component pattern(智慧元件和木偶元件或者我認為是容器元件和展示元件)。
  3. 它們鼓勵程式碼應該有更多的複用性和模組化。
  4. 不鼓勵程式碼過長,變得複雜且負責太多的事情。
  5. 它們允許React通過避免不必要的檢查和記憶體分配來進行效能優化。