先从 renderProps 说起吧
在 class component 各种生命周期盛行的时候,没有 state 的函数通常来做展示型组件,所以社区就有人想出增强 function component 功能的方法。
react-powerplug 是一个 renderProps 的工具库,来看下它的代码
1 2 3 4 5 6 7 8 9 10 11
| <Toggle initial={false}> {({ on, toggle }) => ( <CheckBox onChange={toggle} checked={on} /> )} </Toggle>
function CheckBox(props) { return <input type="checkbox" {...props} /> }
|
对比下 class component 的写法,是少了很多的 state 和一些回调函数了
1 2 3 4 5 6 7 8 9 10
| state = { checked: false }
handleChange = () => { this.setState({ checked: !this.state.checked }) };
render() { const { checked } = this.state; return ( <CheckBox onChange={this.handleChange} checked={checked} /> ) }
|
不过大家应该可以看出一点局限性了,比如 Toggle
只适合做显隐控制这些,业务一些状态可能并不适用。
还有存在嵌套的场景,最新版本去掉了 compose
聚合方法,那只能另寻出路了。
1 2 3 4 5 6 7 8 9 10 11 12 13
| function App() { return ( <Counter initial={5}> {counter => ( <Toggle initial={false}> {({ on, toggle }) => ( <CheckBox counter={counter} onChange={toggle} checked={on} /> )} </Toggle> )} </Counter> ); }
|
解决嵌套问题的epitath
1 2 3 4 5
| const App = epitath(function*() { const { counter } = yield <Counter />; const { on, toggle } = yield <Toggle />; return <CheckBox counter={counter} onChange={toggle} checked={on} />; });
|
epitath 其源码一共40行,看看是如何实现的。
核心就在于 immutable 的 generator
+ React.cloneElement
1 2 3
| const compose = ({ next, value }) => next ? React.cloneElement(value, null, values => compose(next(values))) : value
|
1 2 3 4 5 6 7 8 9 10
| yield A yield B yield C
<A> <B> <C /> <B /> <A />
|
Hooks
Hooks 的出现,替代了 mixin, HOC 复用代码的方式。
在上节中我们说到 Hooks 就和普通 function component 一样,是有 capture value 特性的。
反映到下面的 demo 上,实际效果并不是从 60 减到 0,而是到达 59 暂停,解决办法在之前也提到过,可以用 useRef
拿到最新的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function Timeout() { const [counter, setCounter] = useState(60); const [start, setStart] = useState(false); useEffect(() => { let intervel; if (start) { intervel = setInterval(() => { setCounter(counter - 1) }, 1000); } return () => clearInterval(intervel) }, [start]) return <> <p>{counter}</p> <button onClick={() => setStart(!start)}>CLICK ME!</button> </> }
|
Hooks 的高复用性,让它用来制作自定义 Hooks 十分方便。