- class组件法的实现
传统Class方式下,很容易想到UNSAFE_componentWillUpdate,将nextProps与当前的props比较便可知道高度是否发生了变化
UNSAFE_componentWillUpdate(nextProps) {
if (this.props.height && nextProps.height && this.props.height !== nextProps.height && ueditor && ueditor.ready) {
if (nextProps.height < pageHeight) {
ueditor.setHeight(nextProps.height);
} else {
ueditor.setHeight(pageHeight);
}
}
}
检测到变化后通过setState立即将最新的值到作为富文本框的高度,完成了功能。
- 使用Hook方式的实现
实现Hooks方式时,因为是函数类型的组件,是没有生命周期的来做这个事情的。如果单单只是检测props的变化,可以这样写:
useEffect(() => {
console.log('height changed', props.height);
}, [props.height])
useEffect(fn, optiopn)会在每次render后执行,第二个参数【props.height】则限定其只在props.height变化时才执行,完美符合文章开头的要求。
因为是在render后执行,所以此时拿到的是最新的props值。如果想获取就数据,则需要借助useRef。
Class组件中下,ref用来绑定对DOM的引用,hooks方式下,根据官方文档的描述,它的作用就灵活些了,并不限定于引用DOM。通过useRef创建的对象其current属性可存储任意值,作用等同于Class上的静态属性。
联想到useEffect是在render后执行,所以可在useEffect中将新的props同步到ref上,而每次render使用的ref是同步之前的旧值,这样就能够在组件中同时获取到新旧的props。下面看代码比较直观:
function Counter() {
const [height, setheight] = useState(0);
const prevHeightRef = useRef();
useEffect(() => {
+ prevHeightRef.current = height;
});
+ const prevHeight = prevHeightRef.current;
return <h1>Now: {height}, before: {prevHeight}</h1>;
}
至此,解决了技术的问题,结合开头的需求,富文本框高度性能优化可以这么写:
import React, { useState, useRef, useEffect } from 'react';
const Ueditor = ({ height }) => {
const prevHeightRef = useRef();
useEffect(() => {
+ prevHeightRef.current = height;
});
if (height !== prevHeightRef.current) {
ueditor.setHeight( prevHeightRef.current);
}
}
export default Ueditor;
- 总结
针对在函数组件中需要获取旧数据的问题,目前是使用useRef间接实现,但从文档上的描述来看,不排除React未来版本中会自带类似usePrevious这样命名的hook开箱即用,就没有那么饿麻烦了。毕竟,获取上一次的值也是比较常见的操作