[React] Recompose 學習筆記
之前已經筆記過 Higher Order Component, pure function 和 compose 了,終於輪到應用在 React 的 Recompose 了!
React Component
React 的元件分成 Class Component 和 Stateless Component (Functional Component)兩種,其中 Stateless 因為所需建立的東西較少,效能差距明顯,而且是可以寫成 pure function 會更利於開發和測試。
Recompose
React 中 Functional Component 雖然效能佳,但比起 Class Component 能做的事太少,於是就有神人開發了一個工具叫 Recompose,利用 Higher Order Component 的方式來加強 Functional Component 的功能。
以下是 Recompose 的介紹
Recompose is a React utility belt for function components and higher-order components. Think of it like lodash for React.
簡單來說希望能透過 Recompose 這個工具,讓大家在開發 React 元件時,能夠保持以 stateless, pure function 的方式開發,減少 setState 的濫用和增進整體效能。
作者有一個演講影片,先記錄一下,有空再去看。
Recompse 例子
以下簡單筆記2個常用的: withState
和 withHandlers
withState()
官方文件如此定義:
withState(
stateName: string,
stateUpdaterName: string,
initialState: any | (props: Object) => any
): HigherOrderComponent
簡單來說就是 Functional(Stateless) Component 既然沒有 state,但有時卻非用 state 不可,只好透過一層元件給予 Functional Component 2個 props 使用: 一個是 state,一個是更新 state 的 function (stateUpdater)。除此之外還需要給這個 state 一個初始值。
特別要注意的是,如果初始值是一個函式的話,會將父元件給予的 props 當作引數餵入此初始函式,回傳值即為初始值。
以下舉一個例子:
const enhance = withState('counter', 'setCounter', props => props.counter);
// 除了原本父元件給的 props 外,還會增加 counter, setCounter 2個 props
const Counter = enhance(({ counter, setCounter }) =>
<div>
Count: {counter}
<button onClick={() => setCounter(n => n + 1)}>++</button>
<button onClick={() => setCounter(n => n - 1)}>--</button>
</div>
)
所以可以簡單看得出來, withState 夾在原本 Counter 的父元件跟 Counter 之間,新增了一個 state 叫 counter
,並設定了一個更新的函式叫 setCounter
(引數為 counter,回傳值會成為 counter 新的值 ),且初始值為從父元件傳過來的 props.counter
。
withHandlers()
官方文件如此定義:
withHandlers(
handlerCreators: {
[handlerName: string]: (props: Object) => Function
} |
handlerCreatorsFactory: (initialProps) => {
[handlerName: string]: (props: Object) => Function
}
): HigherOrderComponent
如果以剛剛 counter 的例子來擴充的話,會長這樣:
const enhance = compose(
withState('counter', 'setCounter', 0),
withHandlers({
increment: ({ setCounter }) => () => setCounter(n => n + 1),
decrement: ({ setCounter }) => () => setCounter(n => n - 1),
reset: ({ setCounter }) => () => setCounter(0)
}))
)
const Counter = enhance(({ counter, increment, decrement, reset }) =>
<div>
Count: {counter}
<button onClick={() => increment() }>++</button>
<button onClick={() => decrement() }>--</button>
<button onClick={() => reset() }>RESET</button>
</div>
)
withState
和 withHandlers
搭配處理表單
表單處理常常需要有一個 state 紀錄目前使用者表單上的輸入值,可以進行即時正確性的確認,也需要 onChange
和 onSubmit
事件的處理。這種情況下,利用withState
和 withHandlers
搭配剛剛好!
const enhance = compose(
withState('value', 'updateValue', ''),
withHandlers({
onChange: props => event => {
props.updateValue(event.target.value)
},
onSubmit: props => event => {
event.preventDefault()
submitForm(props.value)
}
})
)
const Form = enhance(({ value, onChange, onSubmit }) =>
<form onSubmit={onSubmit}>
<label>Value
<input type="text" value={value} onChange={onChange} />
</label>
</form>
)
這邊特別注意的是, withState
中的 value
, updateValue
,對於 withHandlers
來說是父元件傳下來的 props,所以調用時是 props.updateValue
和 props.Value
,當然也可以使用前一個 counter 例子中的解構賦值。以下2種不同方式比較:
onChange: props => event => {
props.updateValue(event.target.value)
}
onChange: ({ updateValue }) => event => {
updateValue(event.target.value)
}
剩下的幾乎還沒什麼用到,等有用熟了再來筆記一下。