函数组件
class 组件只接受一个 props ,没有其他逻辑,可以使用函数组件
- 纯函数,输入 props ,输出 JSX
- 没有实例,没有生命周期,没有 state
- 不能扩展其他方法
非受控组件(相对于受控组件)
- ref
- input 的值不受 state 的控制,只是赋了个默认的初始值 ```jsx import React, { LegacyRef } from “react”;
interface Props {}
interface StateType { count: number; name: string; }
export class Header extends React.Component
this.state = {
count: 0,
name: "jesse",
};
this.nameRef = React.createRef();
this.handleClick = this.handleClick.bind(this);
}
handleClick() { const elem = this.nameRef.current; console.log(elem.value); }
render() { const { name } = this.state; return (
{/ 使用 defaultValue ,而不是 value ,使用 ref /}
{/ state 不会随着改变 /}
state.name: {name}
);
}
}
- defaultValue,defaultChecked
- 手动操作 DOM 元素
使用场景<br />必须要 DOM 操作,setState 实现不了,使用非受控组件<br />文件上传:`<input type="file">`<br />富文本编辑器,需要传入 DOM 元素
<a name="5VGKX"></a>
#### Portals
传送门<br />让组件渲染到父组件之外
```jsx
import React from "react";
import ReactDOM from "react-dom";
interface Props {}
interface StateType {}
export class B extends React.Component<Props, StateType> {
constructor(props: Props) {
super(props);
this.state = {};
}
render() {
return ReactDOM.createPortal(
// {this.props.children} 类似于 vue 的 slot
<div className="b-modal">{this.props.children}</div>,
document.body
);
}
}
使用场景
overflow: hidden
- 父组件的
z-index
值大小 fixed
需要放在body
第一层级
context
上下文
import { Button } from "antd";
import React from "react";
import ReactDOM from "react-dom";
interface Props {}
interface StateType {
theme: string;
}
const ThemeContext = React.createContext("light");
// 函数式组件
function ThemeLink(props: Props) {
return (
<ThemeContext.Consumer>
{(value) => <p>link theme is {value}</p>}
</ThemeContext.Consumer>
);
}
class ThemeButton extends React.Component {
// 写法1:指定 contextType
static contextType = ThemeContext;
render() {
const theme = this.context;
return (
<div>
<p>button theme is {theme}</p>
</div>
);
}
}
// 写法2:指定 contextType
// ThemeButton.contextType = ThemeContext;
function ToolBar(props: Props) {
return (
<div>
<ThemeButton />
<ThemeLink />
</div>
);
}
export class C extends React.Component<Props, StateType> {
constructor(props: Props) {
super(props);
this.state = {
theme: "light",
};
}
changeTheme = () => {
this.setState({
theme: this.state.theme === "light" ? "dark" : "light",
});
};
render() {
const { theme } = this.state;
return (
<ThemeContext.Provider value={theme}>
<ToolBar />
<hr />
<Button onClick={this.changeTheme}>change theme</Button>
</ThemeContext.Provider>
);
}
}
使用场景
- 主题
- 语言
- 认证的用户
异步组件
import()
React.lazy
React.Suspence
```jsx const C = React.lazy(() => import(“components/header/context”));
<a name="wNhoE"></a>
#### 性能优化(对 React 更加重要)
- `SCU`
react 为什么不内部作对比,而是通过 SCU 去让用户做操作?
- 重点:react 默认:父组件更新,子组件无条件更新!
- 避免不规范的写法,或者违反了不可变值
SCU 一定要每次都用吗?
- 需要才优化
SCU 默认返回 true , react 默认重新渲染所有组件<br />必须配合不可变值一起使用<br />有性能问题,再考虑使用
```jsx
shouldComponentUpdate(
nextProps: Readonly<Props>,
nextStates: Readonly<StateType>
): boolean {
if (nextStates.theme !== this.state.theme) {
// 可以渲染
return true;
}
// 不重复渲染
return false;
}
PureComponent
和React.memo
- 纯组件
- SCU 实现浅比较
- 尽量不要做深度比较
React.PureComponent
- 函数式组件
React.memo
- 不可变值
[immutable.js](https://immutable-js.com/)
HOC 高阶组件
就是一个函数,接收一个组件作为参数,返回一个新的函数。
工厂模式
模式简单,增加组件层级
import React from "react";
interface HOCProps {
x: number;
y: number;
}
const withMouse = <P extends HOCProps>(Component: React.ComponentType<P>) => {
class HOC extends React.Component {
constructor(props: P) {
super(props);
this.state = { x: 0, y: 0 };
}
onMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {
this.setState({
x: event.clientX,
y: event.clientY,
});
};
render() {
return (
<div style={{ height: "100px" }} onMouseMove={this.onMouseMove}>
{/* 透传所有 props , 增加 mouse 属性 */}
<Component {...(this.props as P)} mouse={this.state} />
</div>
);
}
}
return HOC;
};
const Mouse = (props: any) => {
const { x, y } = props.mouse;
return (
<div style={{ height: "100px" }}>
<h1>
x: {x}, y: {y}
</h1>
</div>
);
};
export default withMouse(Mouse);
Render Props
通过一个函数将 class
组件中的 state
作为 props
传递给纯函数式组件
代码简洁,学习成本高
import React from "react";
interface State {
x: number;
y: number;
}
interface Props {
render: (state: State) => JSX.Element
}
class Mouse extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { x: 0, y: 0 };
}
onMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {
this.setState({
x: event.clientX,
y: event.clientY,
});
};
render() {
return (
<div style={{ height: "100px" }} onMouseMove={this.onMouseMove}>
{/* 将 state 作为 props 传递给 render 函数 */}
{this.props.render(this.state)}
</div>
);
}
}
// Mouse.propTypes = {
// render: PropTypes.func.isRequired,
// };
const Ap = () => (
<div style={{ height: "100px" }}>
<Mouse
// render 是一个函数组件
render={({ x, y }: State) => (
<h1>
mouse position is x: {x}, y: {y}
</h1>
)}
/>
</div>
);
export default Ap