高阶组件
封装一个名为 withAuthentication 的 HOC,它可以在需要进行身份验证的组件中注入认证逻辑。这样,当我们某个组件需要身份验证才能访问的时候,我们就不需要重复编写认证逻辑了。
import React from 'react';
// 1. 定义一个高阶组件 withAuthentication
function withAuthentication(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false
};
}
componentDidMount() {
// 模拟身份验证逻辑
setTimeout(() => {
this.setState({ isAuthenticated: true });
}, 2000);
}
render() {
const { isAuthenticated } = this.state;
// 根据身份验证状态进行渲染
return isAuthenticated ? (
<WrappedComponent {...this.props} />
) : (
<div>Loading...</div>
);
}
};
}
// 2. 封装需要进行身份验证的组件
class ProtectedComponent extends React.Component {
render() {
return <div>Protected content</div>;
}
}
// 3. 使用 withAuthentication HOC 对 ProtectedComponent 进行保护
const AuthProtectedComponent = withAuthentication(ProtectedComponent);
// 4. 在应用中使用 AuthProtectedComponent
function App() {
return (
<div>
<h1>My App</h1>
<AuthProtectedComponent />
</div>
);
}
RenderProps 技术模式
在 React 中,Render Props 是一种技术模式,用于通过组件的 prop 传递函数,从而实现组件之间的代码共享和逻辑复用。使用 Render Props 可以让组件变得更灵活和可配置
运用场景:封装一个名为 MouseTracker 的组件,它可以追踪鼠标的位置,并将当前鼠标的坐标传递给它的子组件进行显示。这样,每当我们需要在某个组件中跟踪鼠标位置的时候,只需要调用这个 MouseTracker 组件即可。
MouseTracker 封装
class MouseTracker extends React.Component {
constructor(props) {
super(props);
this.state = {
x: 0,
y: 0
};
}
handleMouseMove = event => {
this.setState({
x: event.clientX,
y: event.clientY
});
};
render() {
return (
<div style={{ height: '100vh' }} onMouseMove= {this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
class App extends React.Component {
render() {
return (
<MouseTracker
render={({ x, y }) => (
<div>
<h1>在这里移动鼠标!</h1>
<p>当前鼠标位置: {x}, {y}</p>
</div>
)}
/>
);
}
}
在组件中复用 MouseTracker 能力
import React, { Component } from "react";
import MouseTracker from "./MouseTracker";
export default class CompA extends Component {
render() {
return (
<MouseTracker
render={({ x, y }) => (
<div>
一个组件(具备自己的功能)
<h3>鼠标x坐标:{x}</h3>
<h3>鼠标y坐标:{y}</h3>
</div>
)}
/>
);
}
}
Fragment和空标签
- 只能有一个唯一根节点
- Fragment 可以包裹内容,但是不会被渲染为真实 DOM 节点
- 也可以使用空标签代替 Fragment,来实现组件根节点不被渲染为真实 DOM 的效果
props.children插槽
ReactDOM.createPortal()传送门
普通的组件,子组件的元素将挂载到父组件的 DOM 节点中。
有时需要将元素渲染到 DOM 中的不同位置上去,这是就用到的 portal 的方法。
import React, { Component } from "react";
import ReactDOM from "react-dom";
class Modal extends Component {
render() {
return ReactDOM.createPortal(
<div
style={{
position: "fixed",
top: 0,
right: 0,
bottom: 0,
left: 0,
backgroundColor: "rgba(0, 0, 0, 0.5)",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<div
style={{
width: "50%",
minHeight: 500,
backgroundColor: "#fff",
}}
>
<header>
{this.props.header}
<span
style={{ float: "right" }}
onClick={() => this.props.onClose()}
>
×
</span>
</header>
<div>{this.props.content}</div>
</div>
</div>,
document.getElementsByTagName("body")[0]
);
}
}
class App extends Component {
state = {
show: false,
};
render() {
return (
<div>
<button onClick={() => this.setState({ show: true })}>
打开模态框
</button>
{this.state.show ? (
<Modal
header="模态框标题"
content="这里是一个自定义的模态框"
onClose={() => this.setState({ show: false })}
/>
) : null}
</div>
);
}
}
export default App;
- 一个 portal 的典型用例是当父组件有
overflow: hidden或z-index样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框:
getDerivedStateFromProps优化渲染性能
- 变化时才执行
import React, { Component } from "react";
export default class Test extends Component {
state = {
msg: "",
reMsg: "",
};
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.msg != prevState.msg) {
console.log("反转字符串");
return {
reMsg: nextProps.msg.split("").reverse().join(""), //保证反转字符串运算,只有在msg发生变化的时候才会执行
msg: nextProps.msg,
};
}
return null; //代表不更新当前组件的state
}
render() {
return <div>Test,{this.state.reMsg}</div>;
}
}
PureComponent
- 使用,识别数据是否发生变化