面试题答案
一键面试1. getDerivedStateFromProps
- 作用:此方法在组件挂载和更新时都会被调用,用于根据新的
props
更新state
。它是一个静态方法,不能访问this
。主要用于在props
变化时同步更新state
,使得state
与props
保持一致。 - 在实时数据交互应用中的使用:在在线协作绘图工具中,当接收到来自服务器的新绘图数据(作为
props
传递进来),可以通过getDerivedStateFromProps
来更新组件的state
,确保本地绘制状态与服务器传来的数据一致。
class DrawingComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
drawingData: []
};
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.newDrawingData!== prevState.drawingData) {
return {
drawingData: nextProps.newDrawingData
};
}
return null;
}
render() {
return (
<div>
{/* 基于 this.state.drawingData 进行绘图渲染 */}
</div>
);
}
}
2. getSnapshotBeforeUpdate
- 作用:在更新发生之前,在
render
之后立即调用,它可以访问更新前的props
和state
,并且返回的值会作为componentDidUpdate
的第三个参数snapshot
传入。常用于在 DOM 更新前捕获一些信息,如滚动位置等。 - 在实时数据交互应用中的使用:在绘图工具中,如果用户在绘图区域滚动,并且希望在更新后保持滚动位置,可以使用
getSnapshotBeforeUpdate
捕获更新前的滚动位置,然后在componentDidUpdate
中恢复滚动位置。
class DrawingComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
drawingData: []
};
this.drawingRef = React.createRef();
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.newDrawingData!== prevState.drawingData) {
return {
drawingData: nextProps.newDrawingData
};
}
return null;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
const drawingArea = this.drawingRef.current;
if (drawingArea) {
return {
scrollTop: drawingArea.scrollTop,
scrollLeft: drawingArea.scrollLeft
};
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
const drawingArea = this.drawingRef.current;
if (drawingArea && snapshot) {
drawingArea.scrollTop = snapshot.scrollTop;
drawingArea.scrollLeft = snapshot.scrollLeft;
}
}
render() {
return (
<div ref={this.drawingRef}>
{/* 基于 this.state.drawingData 进行绘图渲染 */}
</div>
);
}
}
3. componentDidUpdate
- 作用:在组件更新后调用,可以访问更新前的
props
和state
。常用于副作用操作,如数据请求、DOM 操作等。 - 在实时数据交互应用中的使用:在绘图工具中,当用户绘制完成后,可能需要将绘制的数据发送到服务器。可以在
componentDidUpdate
中判断绘制数据是否发生变化,如果变化则发送数据到服务器。
class DrawingComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
drawingData: []
};
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.newDrawingData!== prevState.drawingData) {
return {
drawingData: nextProps.newDrawingData
};
}
return null;
}
componentDidUpdate(prevProps, prevState) {
if (prevState.drawingData!== this.state.drawingData) {
// 发送数据到服务器
fetch('/api/saveDrawing', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ drawingData: this.state.drawingData })
});
}
}
render() {
return (
<div>
{/* 基于 this.state.drawingData 进行绘图渲染 */}
</div>
);
}
}
设计模式
- 单向数据流模式:在 React 应用中,始终保持单向数据流,即数据从父组件通过
props
流向子组件,子组件通过回调函数通知父组件状态变化。在绘图工具中,顶层组件管理绘图数据的state
,通过props
将数据传递给负责绘制的子组件,子组件通过回调函数通知顶层组件数据更新,顶层组件再通过getDerivedStateFromProps
更新state
。 - 防抖(Debounce)和节流(Throttle):对于频繁触发的用户操作,如绘图时的鼠标移动事件,使用防抖或节流技术来减少不必要的更新。例如,在用户绘制线条时,使用节流确保每 100ms 才更新一次绘制数据,避免大量高频异步请求。
import throttle from 'lodash/throttle';
class DrawingComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
drawingData: []
};
this.handleDraw = throttle(this.handleDraw.bind(this), 100);
}
handleDraw(event) {
// 更新绘制数据逻辑
this.setState((prevState) => {
// 根据鼠标位置等更新 drawingData
return {
drawingData: prevState.drawingData.concat([/* 新的绘制点 */])
};
});
}
render() {
return (
<div onMouseMove={this.handleDraw}>
{/* 基于 this.state.drawingData 进行绘图渲染 */}
</div>
);
}
}
通过合理使用这三个生命周期方法以及相应的设计模式,可以在复杂异步业务逻辑场景下确保数据一致性、避免竞态条件,并保证用户操作的流畅性。