React中的HOC
1组件是将props转换为UI,而高阶组件是将组件转换为另一个组件
2HOC本质就是一个函数,该函数接受一个组件作为参数,并返回一个新的组件,这是一种模式
3我们可以称之为纯组件,因为他们以接受任何动态提供的子组件,但他们不会修改或复制其输入组件中的任何行为
HOC用例:
1.代码复用,逻辑抽象化
2.渲染劫持
3.抽象化和操作状态(state)
4.操作属性props
下面是官方解释∶
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
高阶组件(HOC)就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件,它只是一种组件的设计模式,这种设计模式是由react自身的组合性质必然产生的。我们将它们称为纯组件,因为它们可以接受任何动态提供的子组件,但它们不会修改或复制其输入组件中的任何行为。
// hoc的定义
function withSubscription(WrappedComponent, selectData) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: selectData(DataSource, props)
};
}
// 一些通用的逻辑处理
render() {
// ... 并使用新数据渲染被包装的组件!
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
// 使用
const BlogPostWithSubscription = withSubscription(BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id));
1)HOC的优缺点
优点∶ 逻辑服用、不影响被包裹组件的内部逻辑。
缺点∶hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被覆盖
2)适用场景
代码复用,逻辑抽象
渲染劫持
State 抽象和更改
Props 更改
3)具体应用例子
权限控制: 利用高阶组件的 条件渲染 特性可以对页面进行权限控制,权限控制一般分为两个维度:页面级别和 页面元素级别
// HOC.js
function withAdminAuth(WrappedComponent) {
return class extends React.Component {
state = {
isAdmin: false,
}
async UNSAFE_componentWillMount() {
const currentRole = await getCurrentUserRole();
this.setState({
isAdmin: currentRole === 'Admin',
});
}
render() {
if (this.state.isAdmin) {
return <WrappedComponent {...this.props} />;
} else {
return (<div>您没有权限查看该页面,请联系管理员!</div>);
}
}
};
}
// pages/page-a.js
class PageA extends React.Component {
constructor(props) {
super(props);
// something here...
}
UNSAFE_componentWillMount() {
// fetching data
}
render() {
// render page with data
}
}
export default withAdminAuth(PageA);
// pages/page-b.js
class PageB extends React.Component {
constructor(props) {
super(props);
// something here...
}
UNSAFE_componentWillMount() {
// fetching data
}
render() {
// render page with data
}
}
export default withAdminAuth(PageB);
组件渲染性能追踪: 借助父组件子组件生命周期规则捕获子组件的生命周期,可以方便的对某个组件的渲染时间进行记录∶
class Home extends React.Component {
render() {
return (<h1>Hello World.</h1>);
}
}
function withTiming(WrappedComponent) {
return class extends WrappedComponent {
constructor(props) {
super(props);
this.start = 0;
this.end = 0;
}
UNSAFE_componentWillMount() {
super.componentWillMount && super.componentWillMount();
this.start = Date.now();
}
componentDidMount() {
super.componentDidMount && super.componentDidMount();
this.end = Date.now();
console.log(`${WrappedComponent.name} 组件渲染时间为 ${this.end - this.start} ms`);
}
render() {
return super.render();
}
};
}
export default withTiming(Home);
注意:withTiming 是利用 反向继承 实现的一个高阶组件,功能是计算被包裹组件(这里是 Home 组件)的渲染时间。
页面复用
const withFetching = fetching => WrappedComponent => {
return class extends React.Component {
state = {
data: [],
}
async UNSAFE_componentWillMount() {
const data = await fetching();
this.setState({
data,
});
}
render() {
return <WrappedComponent data={this.state.data} {...this.props} />;
}
}
}
// pages/page-a.js
export default withFetching(fetching('science-fiction'))(MovieList);
// pages/page-b.js
export default withFetching(fetching('action'))(MovieList);
// pages/page-other.js
export default withFetching(fetching('some-other-type'))(MovieList);
好了就到这里吧!!