react的中 对于一些复用的节点,我们可以抽成一个组件,而对于一些复用的逻辑,我们也可以抽象化这个逻辑来优化代码,主要有三种方法,HOC,render props,和自定义hook
HOC
HOC 就是高阶组件吗,之前有博客介绍了的,虽然写的有点烂但我这里就不赘述了,这里用一个计数器的demo,直接上高阶组件实现计数器的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import React from 'react' import {View, Text,Button} from 'react-native' function Count({count,add,minus}) { return ( <View style={{flex:1,alignItems:'center',justifyContent:'center'}}> <Text>You clicked {count} times</Text> <Button onPress={add} title={'add'}/> <Button onPress={minus} title={'minus'}/> <Button onPress={changeTheme} title={'ChangeTheme'}/> </View> ); } const countNumber=(initNumber)=> (WrappedComponent)=> class CountNumber extends React.Component { state = {count: initNumber}; add = () => this.setState({count: this.state.count + 1}); minus = () => this.setState({count: this.state.count - 1}); render() { return <WrappedComponent {...this.props} count={this.state.count} add={this.add.bind(this)} minus={this.minus.bind(this)} /> } }; export default countNumber(0)(Count);
|
优点:
可以看到,高阶组件是把逻辑和UI分开了,Count组件指负责渲染UI,被传入HOC中才有了计数的逻辑,这很好的维护了内层组件的状态,降低了耦合度
缺点:
- 注意一下HOC的state是写死的,也就是说传入给Count组件的prop是写死的,这就有可能产生命名冲突,覆盖掉Count组件原有的props
- HOC是链式调用,会导致错误难以定位
render props
先直接上代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import React from 'react' import {View, Text,Button} from 'react-native' export default function RenderProps() { return ( <View style={{flex:1,alignItems:'center',justifyContent:'center'}}> <CountNumber initNumber={0} render={ ({count,add,minus})=> <> <Text>You clicked {count} times</Text> <Button onPress={add} title={'add'}/> <Button onPress={minus} title={'minus'}/> <Button onPress={changeTheme} title={'ChangeTheme'}/> </> }> </CountNumber> </View> ); } class CountNumber extends React.Component{ state={count:this.props.initNumber}; add=()=>this.setState({count:this.state.count+1}); minus=()=>this.setState({count:this.state.count-1}); render(){ return this.props.render({ count: this.state.count, add: this.add, minus:this.minus }) } }
|
这样也实现了逻辑复用,还留下了一个“插槽”,也就是预留位置,缺点就是不能在return语句外访问数据,同时用的过多的话会跟HOC差不多,HOC是过长的链式调用形成异常栈,而render props则会形成潜逃地狱
Hook
最后看一看最新的自定义hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import React,{useState} from 'react' import {View, Text,Button} from 'react-native'
export default function HookCount() { const [count,addCount,minusCount] = useCountNumber(0); return ( <View style={{backgroundColor:theme,flex:1,alignItems:'center',justifyContent:'center'}}> <Text>You clicked {count} times</Text> <Button onPress={addCount} title={'add'}/> <Button onPress={minusCount} title={'minus'}/> <Button onPress={changeTheme} title={'ChangeTheme'}/> </View> ); }
function useCountNumber(initNumber) { const [count, setCount] = useState(initNumber); const addCount=()=> setCount(count + 1); const minusCount=()=>setCount(count -1); return [ count, addCount, minusCount ] }
|
反正 hook作为最新的语法,最好还是多用他,但也不能完全代替
- Hooks:
- 替代 Class 的大部分用例,除了 getSnapshotBeforeUpdate 和 componentDidCatch 还不支持。
- 提取复用逻辑。除了有明确父子关系的,其他场景都可以使用 Hooks。
- Render Props:在组件渲染上拥有更高的自由度,可以根据父组件提供的数据进行动态渲染。适合有明确父子关系的场景。
- 高阶组件:适合用来做注入,并且生成一个新的可复用组件。适合用来写插件。