React HOC
爱思考的猪 人气:01. 概念
高阶组件和高阶函数的类似,使用函数接收一个组件,并返回一个组件。
function withList(WrapComponent) { return class extends Component { render() { return <div><WrapComponent {...this.props}/></div>; } } };
高阶组件主要用作于逻辑的封装、拦截渲染、拦截生命周期:获取渲染性能,日志打点等,安按照实现方式可以分为属性代理和反向继承两种。
2. 属性代理
属性代理的作用:
- 代理props
- 条件渲染
- 添加状态(state)
- 封装一些通用的逻辑
2.1 代理props
function withList(WrapComponent) { const data = [{ id: '1', text: '测试1' }, { id: '2', text: '测试2' }, { id: '3', text: '测试3' }, { id: '4', text: '测试4' }, { id: '5', text: '测试5' }] return class extends Component { render() { return <div> {this.props.data.length > 0 ? <WrapComponent {...this.props} data={data} /> : <span>{emptyText}</span>} </div>; } } }; class List extends Component { render() { return ( <ul> {this.props.data.map(item => { return <li key={item.id}>{item.text}</li> })} </ul> ) } }; export default withList(List);
2.2 条件渲染
function withList(WrapComponent, emptyText) { return class extends Component { render() { return <div> {this.props.data.length>0 ? <WrapComponent {...this.props}/> : <span>{emptyText}</span>} </div>; } } }; class List extends Component { render() { return ( <ul> {this.props.data.map(item => { return <li key={item.id}>{item.text}</li> })} </ul> ) } }; export default withList(List,'暂无数据');
2.3 添加状态
利用这一点可以将非受控组件转为受控组件
import React, { Component } from 'react' class Input extends Component { render() { return ( <input value={this.props.value} /> ) } }; function withInput(WrapComponent) { return class extends Component { state = { value: this.props.value } onChange = (value) => { this.setState({ value }); } render() { return <WrapComponent {...this.props} value={this.state.value} onChange={this.onChange}/>; } } }; export default withInput(Input);
3. 反向继承
- 反向继承的作用
- 拦截渲染
- 代理props
- 劫持生命周期函数
- 操作state
- 修改react树
3.1 拦截渲染
function withList(WrapComponent) { return class extends WrapComponent { render() { return <div> <span>通过反向继承拦截渲染</span> {super.render()} </div>; } } };
3.2 劫持生命周期
function withList(WrapComponent) { return class extends WrapComponent { componentDidMount(){ if(super.componentDidMount){ super.componentDidMount.apply(this); }; console.log('拦截生命周期'); } render() { return <div> <span>通过反向继承拦截渲染</span> {super.render()} </div>; } } };
3.3 操作state
import React, { Component } from 'react'; function withList(WrapComponent) { return class extends WrapComponent { constructor(props) { super(props); this.state.data = []; //将列表数据置空 } render() { return <div>{super.render()}</div> } } }; class List extends Component { state = { data: [{ id: '1', text: '测试1' }, { id: '2', text: '测试2' }, { id: '3', text: '测试3' }, { id: '4', text: '测试4' }, { id: '5', text: '测试5' }], } render() { return ( <ul> {this.state.data.map(item => { return <li key={item.id}>{item.text}</li> })} </ul> ) } }; export default withList(List);
3.4 修改react树
import React, { Component } from 'react'; function withList(WrapComponent) { return class extends WrapComponent { render() { const tree = super.render(); let newProps = { ...tree.props }; if (tree.type === 'ul') { newProps.value = 'value'; } return React.cloneElement(tree, newProps, newProps.children); } } }; class List extends Component { render() { return ( <ul> {this.props.data.map(item => { return <li key={item.id}>{item.text}</li> })} </ul> ) } }; export default withList(List);
3.5 记录渲染性能
function withTime(WrapComponent) { return class extends WrapComponent { constructor(props) { super(props); this.start = 0; this.end = 0 } componentWillMount() { if (super.componentWillMount) { super.componentWillMount.call(this); }; this.start = Date.now(); } componentDidMount() { if (super.componentDidMount) { super.componentDidMount.call(this); }; this.end = Date.now(); console.log(`渲染的时间为:${(this.end - this.start) / 1000}秒`) } render() { return super.render(); } } };
4. 使用装饰器
4.1 安装和配置
首先执行npm run eject暴露出webpack配置,然后安装装饰器插件
yarn add @babel/plugin-proposal-decoreators;
最后在package.json中的babel配置中添加一下配置然后重新项目
"babel": { "presets": [ "react-app" ], "plugins":[ [ "@babel/plugin-proposal-decorators", {"legacy":true} ] ] }
配置完之后如果有报红需要配置一下:
文件-> 首选项 -> 搜索 ExperimentalDecorators 勾选上之后红线就消失了
4.2 使用
@withList class List extends Component { render() { return ( <ul> {this.props.data.map(item => { return <li key={item.id}>{item.text}</li> })} </ul> ) } };
5.总结
- 高阶组件的作用有代复用、代理属性、拦截渲染、劫持生命周期
- 反向继承能直接操作和拦截组件的state和生命周期,功能比属性代理更加强大
加载全部内容