一、引言
经过这周需求的开发,我发现自己在编写代码的过程中不太关注代码的复用性和可维护性,不经意间就直接简单的复制粘贴就完事,这样看起来是实现了功能,但是却为以后的开发留下了很大的隐患。所以,这周我特地结合了自己开发过程中的问题,简单了了解了一下关于提高React代码复用性的两种方法。
二、使用React高阶组件来提升代码的可复用性
先介绍一下什么是React的高阶组件,
高阶组件是一个函数,接收一个组件,然后返回一个新的组件。
const EnhancedComponent = highOrderComponent(WrappedComponent);
要记住的是,虽然名称是高阶组件,但是高阶组件不是组件,而是函数!
既然是函数,那就可以有参数,有返回值。从上面可以看出,这个函数接收一个组件WrappedComponent作为参数 ,返回加工过的新组件EnhancedComponent。其实高阶组件就是设计模式里的装饰者模式。
可以说,组件是把 props 转化成 UI,而高阶组件是把一个组件转化成另外一个组件。
下面是一个简单的高阶组件:
import React, { Component } from 'react';
export default (WrappedComponent) => {
return class EnhancedComponent extends Component {
// do something
render() {
return <WrappedComponent />; //HOC返回的是一个新的组件
}
}
}
其实,这只是其中的一种高阶组件,这个时候高阶组件复用的是组件,也就是说在一个通用的组件中添加额外的逻辑,然后返回一个添加了额外方法和参数的新组件。
另外一种高阶组件复用的是多个组件中相同的逻辑,返回一个新的组件。我在开发中使用到的就是这种形式的高阶组件。它是这样的形式:
//组件一
class Component1 extends React.Component {
...
}
//组件二
class Component2 extends React.Component {
...
}
//假设组件一和组件二都需要使用相同的函数foo
//设计一个可以复用foo的高阶组件
const HOCComponent = (Component, props) => {
const obj = {
foo1() {},
foo2() {},
... //这里表示想添加的其他参数
};
const newprops = Object.assign({}, obj, props);
return <Component {...newprops}/>
}
//使用该高阶组件
let newComponent1 = HOCComponent(Component1, this.props);
let newComponent2 = HOCComponent(Component2, this.props);
这样就可以实现复用两个组件相同的函数或者其他的参数了,不用在每个组件中都写重复的代码。
三、使用React Hook:useState()来提升代码的可复用性
先简单介绍一下useState这个hook,
用法:
const [state, setState] = useState(initialState);
返回值:state,更新state的函数setState
参数:初始的state:initialState
因为useState这个Hook诞生之前,如果想使用state必须得定义类组件,函数组件无法使用state,但是组件的演变肯定是往轻量化这个方向演变的,所以useState就可以是函数组件也可以使用state。
来看一下下面这个例子:
有一个这样的场景:
现在有 小A,小B 两位同学,每位同学都处于未穿鞋的状态,小A穿鞋需要2s,小B穿鞋需要5s,在页面一中用文字描述两位同学的穿鞋状态变更( 如果小A正在穿鞋中,则在页面上显示 '小A正在穿鞋子',如果小A已经穿好了鞋子,则将文字替换为 '小A已经穿好鞋子')
使用class组件实现是这样的:
import React from "react";
class Page extends React.Component {
state = {
data: [
{ id: 1, name: "小A", time: "2000" },
{ id: 2, name: "小B", time: "5000" }
]
};
start(item) {
this.setState({
[item.id]: "穿鞋子"
});
setTimeout(() => {
this.setState({
[item.id]: "穿好鞋子"
});
}, item.time);
}
componentDidMount() {
this.state.data.forEach(item => {
this.start(item);
});
}
render() {
return (
<div>
{this.state.data.map(item => {
return (
<h1 key={item.id}>
{this.state[item.id] === "穿鞋子"
? `${item.name}正在穿鞋子...`
: `${item.name}已经穿好鞋子了`}
</h1>
);
})}
</div>
);
}
}
export default Page;
使用Hook组件实现是这样的:
自定义Hook如下:
- src/useHook.js
import React, { useState } from "react";
function useHook(item) {
const [status, setStatus] = useState("穿鞋子");
setTimeout(() => {
setStatus("穿好鞋子");
}, item.time);
return (
<h1 key={item.id}>
{status === "穿鞋子"
? `${item.name}正在穿鞋子...`
: `${item.name}已经穿好鞋子了`}
</h1>
);
}
export default useHook;
引用hook的函数组件
- src/hookDemo1.js
import React from "react";
import useHook from "./useHook";
function Page() {
const data = [
{ id: 1, name: "小A", time: "2000" },
{ id: 2, name: "小B", time: "5000" }
];
return (
<div>
{data.map(item => {
return useHook(item);
})}
</div>
);
}
export default Page;
看起来并没有什么区别嘛,代码量也没有减少。
但是,如果小C和小D也要实现这样的描述,使用定义好的Hook就简单多了。
- src/hookDemo2.js
import React from "react";
import useHook from "./useHook";
function Page() {
const data = [
{ id: 1, name: "小C", time: "4000" },
{ id: 2, name: "小D", time: "8000" }
];
return (
<div style={{ color: "lightblue" }}>
{data.map(item => {
return useHook(item);
})}
</div>
);
}
export default Page;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。