fix: 新增react学习
This commit is contained in:
parent
cf4958e806
commit
a7ec84e131
@ -14,14 +14,14 @@ group:
|
||||
|
||||
世界知名三大框架之一,我认为热度目前为首吧
|
||||
|
||||
### 设计原则
|
||||
### iPhone 上的秒表
|
||||
|
||||
设计组件的几个原则:
|
||||
|
||||
1. 保持接口小,props 数量要少
|
||||
2. 根据数据边界划分组件,充分利用组合
|
||||
3. 把 state 往上层组件提取,让下层组件只需要实现为纯函数
|
||||
|
||||
举例,iPhone 上的秒表:
|
||||
|
||||
```jsx
|
||||
import React, { useState } from 'react';
|
||||
|
||||
@ -40,7 +40,7 @@ const MajorClock = ({ ms = 0 }) => {
|
||||
return result;
|
||||
};
|
||||
|
||||
return <h1>{ms2Time(ms)}</h1>;
|
||||
return <h1 style={{ textAlign: 'center', color: 'red' }}>{ms2Time(ms)}</h1>;
|
||||
};
|
||||
|
||||
// 返回所有记次jsx
|
||||
@ -65,18 +65,41 @@ const ControlButton = ({
|
||||
['normal', '#aaa'],
|
||||
]);
|
||||
|
||||
const contStyle = {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-around',
|
||||
};
|
||||
|
||||
const btnStyle = {
|
||||
width: '64px',
|
||||
height: '64px',
|
||||
lineHeight: '64px',
|
||||
textAlign: 'center',
|
||||
fontWeight: '300',
|
||||
borderRadius: '99px',
|
||||
border: '3px solid #b4a078',
|
||||
};
|
||||
|
||||
if (activated) {
|
||||
return (
|
||||
<div>
|
||||
<button onClick={onSplit}>计次</button>
|
||||
<button onClick={onPause}>停止</button>
|
||||
<div style={contStyle}>
|
||||
<button style={btnStyle} onClick={onSplit}>
|
||||
计次
|
||||
</button>
|
||||
<button style={btnStyle} onClick={onPause}>
|
||||
停止
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<button onClick={onReset}>复位</button>
|
||||
<button onClick={onStart}>启动</button>
|
||||
<div style={contStyle}>
|
||||
<button style={btnStyle} onClick={onReset}>
|
||||
复位
|
||||
</button>
|
||||
<button style={btnStyle} onClick={onStart}>
|
||||
启动
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -89,9 +112,9 @@ export default class StopWatch extends React.Component {
|
||||
|
||||
state = {
|
||||
isStarted: false,
|
||||
startTime: null,
|
||||
currentTime: null,
|
||||
spilts: [],
|
||||
startTime: 0,
|
||||
currentTime: 0,
|
||||
splits: [],
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -99,6 +122,7 @@ export default class StopWatch extends React.Component {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<h2 style={{ textAlign: 'center', color: 'green' }}>秒表</h2>
|
||||
<MajorClock ms={currentTime - startTime} />
|
||||
<ControlButton
|
||||
activated={isStarted}
|
||||
@ -139,6 +163,22 @@ export default class StopWatch extends React.Component {
|
||||
}
|
||||
```
|
||||
|
||||
## 无状态组件(PureComponent)
|
||||
|
||||
为了防止相同的 props 多次渲染,可以通过更改为 PureComponent 来实现(函数组件可以使用 memo ),从而减少性能的浪费
|
||||
|
||||
```js
|
||||
// 类组件
|
||||
class Demo extends React.PureComponent {
|
||||
render() {
|
||||
return <div>我是一个无状态组件</div>;
|
||||
}
|
||||
}
|
||||
|
||||
// 函数组件
|
||||
const Demo = React.memo(() => <div>我是一个无状态组件</div>);
|
||||
```
|
||||
|
||||
## 高阶组件(HOC)
|
||||
|
||||
高阶组件的几个原则:
|
||||
@ -147,28 +187,158 @@ export default class StopWatch extends React.Component {
|
||||
2. 结果必须是一个新的 React 组件,新组件的 JSX 部分包含作为参数的组件
|
||||
3. 一般需要把传给自己的 props 转手传递给作为参数的组件
|
||||
|
||||
> 一般会带 with 前缀
|
||||
|
||||
### 普通用法
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
|
||||
class Demo extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
const getUserId = () => {
|
||||
return true;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { store } = this.props;
|
||||
return <div>艹 {store}</div>;
|
||||
}
|
||||
}
|
||||
const LoginBtn = () => {
|
||||
return <div>退出登录</div>;
|
||||
};
|
||||
|
||||
const withFuckU = (Component) => {
|
||||
const ShoppingCar = () => {
|
||||
return <div>购物车</div>;
|
||||
};
|
||||
|
||||
const withLogin = (Component) => {
|
||||
const NewComponent = (props) => {
|
||||
return <Component {...props} store="fuck you" />;
|
||||
if (getUserId()) {
|
||||
return <Component {...props} />;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return NewComponent;
|
||||
};
|
||||
|
||||
export default withFuckU(Demo);
|
||||
const LoginButton = withLogin(LoginBtn);
|
||||
const LoginCar = withLogin(ShoppingCar);
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<LoginButton />
|
||||
<LoginCar />
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
### 高级用法
|
||||
|
||||
借鉴上文的 withLogin,根据用户是否选择登录渲染合适的组件:
|
||||
|
||||
```js
|
||||
const withLoginAndLogout = (ComponentForLogin, ComponentForLogout) => {
|
||||
const NewComponent = (props) => {
|
||||
if (getUserId()) {
|
||||
return <ComponentForLogin {...props} />;
|
||||
} else {
|
||||
return <ComponentForLogout {...props} />;
|
||||
}
|
||||
};
|
||||
return NewComponent;
|
||||
};
|
||||
|
||||
const LoginBtn = () => {
|
||||
return <div>登录</div>;
|
||||
};
|
||||
|
||||
const LogoutBtn = () => {
|
||||
return <div>退出登录</div>;
|
||||
};
|
||||
|
||||
// 通过条件判断 退出(登录)按钮
|
||||
const TopButtons = withLoginAndLogout(LogoutBtn, LoginBtn);
|
||||
```
|
||||
|
||||
### 链式调用
|
||||
|
||||
```js
|
||||
// 示例 1
|
||||
const SuperX = withMethod3(withMethod2(withMethod1(x)));
|
||||
|
||||
// 示例 2
|
||||
const compose = (...funcs) {
|
||||
if (funcs.length === 0) return arg => arg
|
||||
|
||||
if (funcs.length === 1) return funcs[0]
|
||||
|
||||
return funcs.reduce((a, b) => (...args) => a(b(...args)))
|
||||
}
|
||||
|
||||
const hoc = compose(withMethod3, withMethod2, withMethod1)
|
||||
const SuperX = hoc(x)
|
||||
```
|
||||
|
||||
## render props 模式
|
||||
|
||||
示例:
|
||||
|
||||
```js
|
||||
const Auth = (props) => {
|
||||
const userName = getUserName();
|
||||
|
||||
if (userName) {
|
||||
const allProps = { userName, ...props };
|
||||
return <React.Fragment>{props.login(allProps)}</React.Fragment>;
|
||||
} else {
|
||||
<React.Fragment>{props.nologin(props)}</React.Fragment>;
|
||||
}
|
||||
};
|
||||
|
||||
// 调用
|
||||
<Auth
|
||||
login={({ userName }) => <h1>Hello {userName}</h1>}
|
||||
nologin={() => <h1>Please login</h1>}
|
||||
/>;
|
||||
```
|
||||
|
||||
## 提供者模式
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
|
||||
const ThemeContext = React.createContext();
|
||||
const ThemeProvider = ThemeContext.Provider;
|
||||
const ThemeConsumer = ThemeContext.Consumer;
|
||||
|
||||
const Title = (props, context) => {
|
||||
return (
|
||||
<ThemeConsumer>
|
||||
{(theme) => <p style={{ color: theme.textColor }}>{props.children}</p>}
|
||||
</ThemeConsumer>
|
||||
);
|
||||
};
|
||||
|
||||
const Paragraph = (props, context) => {
|
||||
return (
|
||||
<ThemeConsumer>
|
||||
{(theme) => <p style={{ color: theme.mainColor }}>{props.children}</p>}
|
||||
</ThemeConsumer>
|
||||
);
|
||||
};
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<div>
|
||||
<Title>这是标题</Title>
|
||||
<Paragraph>这是正文</Paragraph>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default (props, context) => {
|
||||
return (
|
||||
<ThemeProvider value={{ mainColor: 'green', textColor: 'red' }}>
|
||||
<Page />
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## 参考资料
|
||||
|
Loading…
Reference in New Issue
Block a user