基于Decorator的React高阶组件的思路分析与实现
在深入react 技术栈一书中,提到了基于Decorator的HOC。而不是直接通过父组件来逐层传递props,因为当业务逻辑越来越复杂的时候,props的传递和维护也将变得困难且冗余。 书里对基于Decorator的HOC没有给出完整的实现,在这里实现并记录一下实现的思路。 整个实现的代码放到了我的Github上,是用来获取豆瓣的电影列表的, 整体思路
书里描述的整体思路,先将整个组件,按照view逻辑抽象为互不重叠的最小的原子组件,使组件间组合更自由。在这里最小的组件就是 组件实现原子组件这是对原书代码稍加修改的SearchInput原子组件,因为没加Icon,所以改了一下(逃),整体思路不变。原子组件没什么可说的,木偶组件就是接收props来实现功能,是对view层逻辑的抽象。 需要一提的是 export default class SearchInput extends PureComponent { static displayName = 'SearchInput' render() { const { onSearch,placeholder } = this.props return ( <div> <p>SearchSelect</p> <div> <Input type="text" placeholder={placeholder} onChange={onSearch} /> </div> </div> ) } } Decorator组件先放代码 const searchDecorator = WrappedComponent => { class SearchDecorator extends Component { constructor(props) { super(props) this.handleSearch = this.handleSearch.bind(this) this.state = { keyword: '' } } handleSearch(e) { this.setState({ keyword: e.target.value }) this.props.onSearch(e) } render() { const { keyword } = this.state return ( <WrappedComponent {...this.props} data={this.props.data} keyword={keyword} onSearch={this.handleSearch} /> ) } } Decorator的作用就是将业务/交互逻辑抽象出来进行了处理,view的逻辑还是交由原子组件来实现,可以看到最后的 这样,视图逻辑就由view层抽象,交互/业务逻辑由Decorator来抽象。 组合组件先上代码。 export default class Selector extends Component { render() { return ( <div> { this.props.children.map((item) => { // SelectInput if (item.type.displayName === 'SelectInput') { ... } // SearchInput if (item.type.displayName === 'SearchInput') { return React.cloneElement(item,{ key: 'searchInput',onSearch: this.props.onSearch,placeholder: this.props.searchPlaceholder } ) } // List if (item.type.displayName === 'List') { ... }) } </div> ) } } 组合组件的children为根据不同业务需要包裹起来的原子组件,组合组件的逻辑处理功能来自于Decorator,各种Decorator的钩子函数或者参数作为props传递给了Selector,Selector再用它们去完成原子组件之间的交互。组合组件通过之前提到的
当我们业务逻辑变得复杂的时候,不要去增加Decorator的复杂度,而是去拼接多个Decorator再通过组合组件去处理具体的业务逻辑,这样能保证Decorator的可复用性。 业务组件const FinalSelector = compose(asyncSelectDecorator,selectedItemDecorator,searchDecorator)(Selector) class SearchSelect extends Component { render() { return ( <FinalSelector {...this.props}> <SelectInput /> <SearchInput /> <List /> </FinalSelector> ) } } class App extends Component { render() { return ( <SearchSelect searchPlaceholder={'请搜索电影'} onSearch={(e) => { console.log(`自定义onSearch: ${e.target.value}`) }} onClick={(text) => { console.log(`自定义onClick: ${text}`) }} url="/v2/movie/in_theaters" /> ) } } 通过 tips在实际的场景中也不能滥用HOC,基于Decorator的HOC一般是用来处理偏数据逻辑的部分,而DOM相关的东西就直接简单粗暴的用父组件就好了。
参考资料
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- flex4 对itemRenderer简单的使用产品管理―――DataGrid渲染
- error: Error parsing XML: unbound prefix
- c# – 迭代并返回连续n个元素的数组
- ruby-on-rails-3 – 如何让rake在没有参数的情况下自动运行
- ruby-on-rails – 列出/链接到Rails中目录的内容
- xstream实现xml与Object之间的自如转换
- 利用JAXB实现XML文件和Java对象之间的转化
- ajax(三) 使用jquery实现ajax
- 多些时间能少写些代码
- cocos2dx ant编译'atoi' is not a member of &