fix: 优化react 设计模式

This commit is contained in:
haishan 2021-11-23 13:33:08 +08:00
parent 79143a69eb
commit cf4958e806
2 changed files with 242 additions and 137 deletions

View File

@ -16,6 +16,7 @@ group:
场景:
一台咖啡机,按需求给不同的咖啡:
- 美式咖啡态american):只吐黑咖啡
- 普通拿铁态(latte):黑咖啡加点奶
- 香草拿铁态vanillaLatte黑咖啡加点奶再加香草糖浆
@ -26,52 +27,51 @@ import React, { useRef, useEffect } from 'react';
class CoffeeMachine {
constructor() {
this.state = 'init'
this.leftMilk = '500ml'
this.state = 'init';
this.leftMilk = '500ml';
}
// 美式
american() {
// 尝试在行为函数里拿到咖啡机实例的信息并输出
console.log('咖啡机现在的牛奶存储量是:', this.leftMilk)
console.log('咖啡机现在的牛奶存储量是:', this.leftMilk);
console.log('我只吐黑咖啡');
return '美式'
return '美式';
}
// 普通拿铁
latte() {
this.american()
this.american();
console.log('加点奶');
return '普通拿铁'
return '普通拿铁';
}
// 香草拿铁
vanillaLatte() {
this.latte();
console.log('再加香草糖浆');
return '香草拿铁'
return '香草拿铁';
}
// 摩卡
mocha() {
this.latte();
console.log('再加巧克力');
return '摩卡'
return '摩卡';
}
changeState(state) {
this.state = state;
if (!this[state]) {
return
return;
}
return this[state]()
return this[state]();
}
}
const mk = new CoffeeMachine()
const mk = new CoffeeMachine();
export default () => <div>咖啡类型:{mk.changeState('mocha')}</div>
export default () => <div>咖啡类型:{mk.changeState('mocha')}</div>;
```
### 观察者模式(发布订阅者模式)
@ -80,51 +80,51 @@ export default () => <div>咖啡类型:{mk.changeState('mocha')}</div>
#### 简单版
```jsx
```js
import React from 'react';
// 主题 保存状态,状态变化之后触发所有观察者对象
class Publisher {
constructor() {
this.state = 0
this.observers = []
this.state = 0;
this.observers = [];
}
getState() {
return this.state
return this.state;
}
setState(state) {
this.state = state
this.notifyAllObservers()
this.state = state;
this.notifyAllObservers();
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
this.observers.forEach((observer) => {
observer.update();
});
}
attach(observer) {
this.observers.push(observer)
this.observers.push(observer);
}
}
// 观察者
class Observer {
constructor(name, publisher) {
this.name = name
this.publisher = publisher
this.publisher.attach(this)
this.name = name;
this.publisher = publisher;
this.publisher.attach(this);
}
update() {
console.log(`${this.name} 更新, state: ${this.publisher.getState()}`)
console.log(`${this.name} 更新, state: ${this.publisher.getState()}`);
}
}
// 测试
let pub = new Publisher()
let o1 = new Observer('o1', pub)
let o2 = new Observer('02', pub)
let pub = new Publisher();
let o1 = new Observer('o1', pub);
let o2 = new Observer('02', pub);
pub.setState(12)
pub.setState(12);
export default () => null
export default () => null;
```
#### 复杂版
@ -152,7 +152,7 @@ class Publisher {
}
})
}
// 通知所有订阅者
notify() {
console.log('通知所有订阅者-执行')
@ -202,7 +202,7 @@ class ProObserver extends Observer {
this.prdState = {}
console.log('ProObserver created')
}
// 重写一个具体的update方法
update(publisher) {
console.log('ProObserver 已执行')
@ -211,7 +211,7 @@ class ProObserver extends Observer {
// 调用工作函数
this.work()
}
// work方法一个专门搬砖的方法
work() {
// 获取需求文档
@ -245,77 +245,121 @@ hanMeiMei.setState(prd)
### 策略模式
和状态模式的区别,策略模式更偏向算法,计算逻辑的封装,状态更偏向定值的判断
#### 简单版
业务场景如下:
马上大促要来了,我们本次大促要做差异化询价。啥是差异化询价?就是说同一个商品,我通过在后台给它设置不同的价格类型,可以让它展示不同的价格。具体的逻辑如下:
* 当价格类型为“预售价”时,满 100 - 20不满 100 打 9 折
* 当价格类型为“大促价”时,满 100 - 30不满 100 打 8 折
* 当价格类型为“返场价”时,满 200 - 50不叠加
* 当价格类型为“尝鲜价”时,直接打 5 折
- 当价格类型为“预售价”时,满 100 - 20不满 100 打 9 折
- 当价格类型为“大促价”时,满 100 - 30不满 100 打 8 折
- 当价格类型为“返场价”时,满 200 - 50不叠加
- 当价格类型为“尝鲜价”时,直接打 5 折
```jsx
import React, { useRef, useEffect } from 'react';
class CalculateMoney {
// 处理预热价
prePrice(originPrice) {
if(originPrice >= 100) {
return originPrice - 20
}
return originPrice * 0.9
// 处理预热价
prePrice(originPrice) {
if (originPrice >= 100) {
return originPrice - 20;
}
return originPrice * 0.9;
}
// 处理大促价
onSalePrice(originPrice) {
if(originPrice >= 100) {
return originPrice - 30
}
return originPrice * 0.8
// 处理大促价
onSalePrice(originPrice) {
if (originPrice >= 100) {
return originPrice - 30;
}
return originPrice * 0.8;
}
// 处理返场价
backPrice(originPrice) {
if(originPrice >= 200) {
return originPrice - 50
}
return originPrice
// 处理返场价
backPrice(originPrice) {
if (originPrice >= 200) {
return originPrice - 50;
}
return originPrice;
}
// 处理尝鲜价
freshPrice(originPrice) {
return originPrice * 0.5
}
// 处理尝鲜价
freshPrice(originPrice) {
return originPrice * 0.5;
}
/**
* type: pre 预售 | onSale 大促 | back 返场 | fresh 尝鲜
* money: 原始金额
**/
static get(type, money) {
switch (type) {
case 'pre':
return this.prototype.prePrice(money)
break
case 'onSale':
return this.prototype.onSalePrice(money)
break;
case 'back':
return this.prototype.backPrice(money)
break;
case 'fresh':
return this.prototype.freshPrice(money)
break;
default:
return
}
/**
* type: pre 预售 | onSale 大促 | back 返场 | fresh 尝鲜
* money: 原始金额
**/
static get(type, money) {
switch (type) {
case 'pre':
return this.prototype.prePrice(money);
break;
case 'onSale':
return this.prototype.onSalePrice(money);
break;
case 'back':
return this.prototype.backPrice(money);
break;
case 'fresh':
return this.prototype.freshPrice(money);
break;
default:
return;
}
}
}
let calculateMoney = CalculateMoney.get('back', 10000)
let calculateMoney = CalculateMoney.get('back', 10000);
// => 4000000
export default () => <div>初始金额10000策略模式{calculateMoney}</div>
export default () => <div>初始金额10000策略模式{calculateMoney}</div>;
```
### 迭代器模式
少有的目的性极强的模式。
举例for...of...就是对 next 的反复调用。
```js
// 自带迭代器语法
const arr = [1,2,3]
const iterator = arr[Symbol.iterator]()
iterator.next() -> { value: 1, done: false}
iterator.next() -> { value: 2, done: false}
iterator.next() -> { value: 3, done: false}
iterator.next() -> { value: undefined, done: true}
// 手撸版迭代器,闭包
const itaratorFunc = (arr: any ) => {
const idx = 0
const len = arr.length
if (Object.prototype.toString.call(arr) !== '[object Array]') throw new Error('请输入正确的数组格式')
return {
next: () => {
var done = idx >= len
var value = !done ? list[idx++] : undefined
return {
done,
value
}
}
}
}
const iterator = itaratorFunc([1,2,3])
const iterator.next()
const iterator.next()
const iterator.next()
```

View File

@ -8,79 +8,138 @@ group:
path: /react
---
## 💊 React
# 💊 React
### 介绍
## 介绍
世界知名三大框架之一,我认为热度目前为首吧
```jsx
import React from 'react';
### 设计原则
class Btn extends React.Component {
constructor({ children }) {
1. 保持接口小props 数量要少
2. 根据数据边界划分组件,充分利用组合
3. 把 state 往上层组件提取,让下层组件只需要实现为纯函数
举例iPhone 上的秒表:
```jsx
import React, { useState } from 'react';
// 时钟组件
const MajorClock = ({ ms = 0 }) => {
const ms2Time = (milliseconds = 0) => {
let time = milliseconds;
const ms = milliseconds % 1000;
time = (milliseconds - ms) / 1000;
const seconds = time % 60;
time = (time - seconds) / 60;
const minutes = time % 60;
const hours = (time - minutes) / 60;
const result = hours + ':' + minutes + ':' + seconds + '.' + ms;
return result;
};
return <h1>{ms2Time(ms)}</h1>;
};
// 返回所有记次jsx
const SplitTimes = ({ list = [] }) => {
return list.map((v, k) => <MajorClock key={k} ms={v} />);
};
// 按钮组件
const ControlButton = ({
children,
type,
activated,
onStart,
onPause,
onSplit,
onReset,
}) => {
const BTN_COLORS = new Map([
['danger', 'red'],
['primary', 'blue'],
['warn', 'yellow'],
['normal', '#aaa'],
]);
if (activated) {
return (
<div>
<button onClick={onSplit}>计次</button>
<button onClick={onPause}>停止</button>
</div>
);
} else {
return (
<div>
<button onClick={onReset}>复位</button>
<button onClick={onStart}>启动</button>
</div>
);
}
};
export default class StopWatch extends React.Component {
constructor() {
super(...arguments);
}
state = {
size: 16,
BTN_COLORS: new Map([
['danger', 'red'],
['primary', 'blue'],
['warn', 'yellow'],
['normal', '#aaa'],
]),
isStarted: false,
startTime: null,
currentTime: null,
spilts: [],
};
componentDidMount() {}
render() {
const { children, type, id } = this.props;
const { size, BTN_COLORS } = this.state;
const { isStarted, splits, currentTime, startTime } = this.state;
return (
<React.Fragment>
<div
id={id}
className="btn"
onClick={() => this.setState({ size: size + 1 })}
>
{children}
</div>
<style jsx>{`
.btn {
cursor: pointer;
display: inline-block;
padding: 20px;
font-size: ${size}px;
text-align: center;
color: ${BTN_COLORS.get(type) || '#eee'};
border: 1px solid #aaa;
}
`}</style>
</React.Fragment>
);
}
}
<MajorClock ms={currentTime - startTime} />
<ControlButton
activated={isStarted}
onStart={() => {
this.setState({
isStarted: true,
startTime: new Date(),
currentTime: new Date(),
});
export default class Demo extends React.Component {
render() {
return (
<React.Fragment>
<h2>秒表</h2>
<Btn id="1" type="normal">
计次
</Btn>
<Btn id="2" type="danger">
停止
</Btn>
this.intervalHandle = setInterval(() => {
this.setState({ currentTime: new Date() });
}, 1000 / 60);
}}
onPause={() => {
clearInterval(this.intervalHandle);
this.setState({
isStarted: false,
});
}}
onReset={() => {
this.setState({
startTime: null,
currentTime: null,
splits: [],
});
}}
onSplit={() => {
this.setState({
splits: [...splits, currentTime - startTime],
});
}}
/>
<SplitTimes list={splits} />
</React.Fragment>
);
}
}
```
### 高阶组件HOC
## 高阶组件HOC
高阶组件的几个原则:
@ -112,4 +171,6 @@ const withFuckU = (Component) => {
export default withFuckU(Demo);
```
react 和设计模式 doing...
## 参考资料
- react 实战:设计模式和最佳实践