react:开闭原则,优雅的组件

react:开闭原则,优雅的组件

一、开闭原则简介

开闭原则是面向对象设计中的一个重要原则,它要求软件实体应当对扩展开放,对修改封闭。这意味着在不修改已有代码的基础上,通过添加新的代码来实现新的功能。在 React 中,这可以通过组件的组合来实现。

二、基础按钮组件

我们首先定义一个基础的按钮组件,它包含按钮的基本功能和样式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Button.tsx
import React from 'react';

interface ButtonProps {
text: string;
onClick: () => void;
style?: React.CSSProperties; // 添加style属性
}

const Button: React.FC<ButtonProps> = ({ text, onClick, style }) => {
return (
<button onClick={onClick} style={{ padding: '10px 20px', fontSize: '16px', ...style }}>
{text}
</button>
);
};

export default Button;

这个基础按钮组件非常简单,它接受 text 和 onClick 两个 Props,分别用于显示按钮文本和处理点击事件。同时,通过style属性,我们可以传递自定义样式。

三、扩展按钮功能

接下来,我们通过扩展基础按钮组件来实现新的功能,而不修改原有的代码。

1. 带图标的按钮

我们创建一个新的IconButton组件,它在基础按钮的基础上添加了一个图标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// IconButton.tsx
import React from 'react';
import Button from './Button';

interface IconButtonProps extends ButtonProps {
icon: React.ReactNode;
}

const IconButton: React.FC<IconButtonProps> = ({ icon, text, onClick, style }) => {
return (
<Button onClick={onClick} style={style}>
{icon} {text}
</Button>
);
};

export default IconButton;

2. 带加载状态的按钮

我们再创建一个LoadingButton组件,它在基础按钮的基础上添加了加载状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// LoadingButton.tsx
import React from 'react';
import Button from './Button';

interface LoadingButtonProps extends ButtonProps {
isLoading: boolean;
}

const LoadingButton: React.FC<LoadingButtonProps> = ({ isLoading, text, onClick, style }) => {
return (
<Button onClick={onClick} disabled={isLoading} style={style}>
{isLoading ? 'Loading...' : text}
</Button>
);
};

export default LoadingButton;

四、样式定制

为了实现不同按钮的不同样式,我们可以通过传递style属性来实现。

1. 创建特定样式的按钮组件

如果需要创建特定样式的按钮组件,可以直接在组件内部定义样式。

创建 RedButton 组件

1
2
3
4
5
6
7
8
9
10
11
// RedButton.tsx
import React from 'react';
import Button from './Button';

const RedButton: React.FC<ButtonProps> = ({ text, onClick }) => {
return (
<Button text={text} onClick={onClick} style={{ backgroundColor: 'red', color: 'white' }} />
);
};

export default RedButton;

创建 GreenButton 组件

1
2
3
4
5
6
7
8
9
10
11
// GreenButton.tsx
import React from 'react';
import Button from './Button';

const GreenButton: React.FC<ButtonProps> = ({ text, onClick }) => {
return (
<Button text={text} onClick={onClick} style={{ backgroundColor: 'green', color: 'white' }} />
);
};

export default GreenButton;

创建 BlueButton 组件

1
2
3
4
5
6
7
8
9
10
11
// BlueButton.tsx
import React from 'react';
import Button from './Button';

const BlueButton: React.FC<ButtonProps> = ({ text, onClick }) => {
return (
<Button text={text} onClick={onClick} style={{ backgroundColor: 'blue', color: 'white' }} />
);
};

export default BlueButton;

五、使用

现在我们可以在应用中使用这些按钮组件。

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
// App.tsx
import React from 'react';
import Button from './Button';
import IconButton from './IconButton';
import LoadingButton from './LoadingButton';
import RedButton from './RedButton';
import GreenButton from './GreenButton';
import BlueButton from './BlueButton';

const App: React.FC = () => {
const handleClick = () => {
console.log('Button clicked');
};

return (
<div>
<BlueButton text="Click Me" onClick={handleClick} />
<GreenButton text="Add" onClick={handleClick} />
<RedButton text="Submit" onClick={handleClick} />
<IconButton icon={<i className="fa fa-plus" />} text="Add with Icon" onClick={handleClick} style={{ backgroundColor: 'orange', color: 'white' }} />
<LoadingButton isLoading={false} text="Loading Button" onClick={handleClick} style={{ backgroundColor: 'purple', color: 'white' }} />
</div>
);
};

export default App;