相信大部分React前端开发者对类组件的编程方式都有长时间的编码经验,对性能优化的方案亦有研究,如PureComponent、Component+ComponentShouldUpdate等,但随着大势所趋我们必须拥抱函数式编程+Hooks,那么我们之前的优化方案如何在函数式编程中得以实施呢?
手头的RN项目正好有一个倒计时的小需求,就梳理一下几个hooks的API,如何帮助我们如何高性能的实现。
脱敏之后的需求为:渲染12:21:01马上开抢倒计时。
我们暂且做个约定,初始化几个参数
const countDownIntervalRef = useRef(null); // 定时器ref
const [hour, setHour] = useState(-1); // 时
const [minute, setMinute] = useState(-1); // 分
const [second, setSecond] = useState(-1); // 秒
组件的重复渲染
有几个场景
- 静态dom
这类组件不会依赖我们的hour、minute、second变化,所以针对他们的重复渲染很有必要,这里我们采用***useMemo***来进行处理。
/**
* 时间组件间隙
*/
const TimeGap = useMemo(() => {
console.log(`${hour}:${minute}:${second}`);
console.log('TimeGap');
return <Text style={[Styles.timeItemText, Styles.timeGapText]}>:</Text>;
}, []);
``
大家应该可以看出来,这串代码没别的作用,只是渲染了一个【:】,没错,就是一个冒号。
那么当倒计时运行起来之后的日志情况如何呢?

没错,初始化的时候打印了一次,之后便没有重复打印。那我们优化之前的代码日志如何呢?
代码如下:
```javascript
const TimeGap = () => {
console.log(`${hour}:${minute}:${second}`);
console.log('TimeGap');
return <Text style={[Styles.timeItemText, Styles.timeGapText]}>:</Text>;
};
日志如下:
相比之下就很明显了,如何这个静态dom的树足够大,那么会衍生出更严重的性能问题。
当然useMemo的用处绝不仅仅如此,我们再写个例子。
// 返回倒计时小时信息
const hourText = useMemo(() => {
if (hour === -1) return '';
return `${hour}小时`;
}, [hour]);
这么做的目的是当minute、second在更新的时候不要触发小时信息的重新渲染。
总结:
useMemo借助依赖项参数帮我们对函数结果进行缓存,当然不局限于return的类型,哪怕是一个component。
函数的重新生成优化
内联函数的使用让我们对函数的重复初始化越来越重视,这里我们借助useCallback来进行优化。
代码如下:
/**
* 计算倒计时
*/
const calculateCountDown = useCallback(() => {
const now = new Date().valueOf();
let tempHour = 0;
let tempMinute = 0;
let tempSecond = 0;
if (startTime >= now) {
tempHour = Math.floor((deadline - now) / (60 * 60 * 1000));
tempMinute = Math.floor(
(startTime - now - tempHour * 60 * 60 * 1000) / (60 * 1000),
);
tempSecond = Math.floor(
(startTime - now - tempHour * 60 * 60 * 1000 - tempMinute * 60 * 1000) /
1000,
);
} else {
clearCountDownInterval();
}
setHour(tempHour);
setMinute(tempMinute);
setSecond(tempSecond);
}, [startTime]);
calculateCountDown是倒数时的执行函数,如果它仅仅是一个普通函数,那么可以试想,在倒计时的生命周期内这个函数每秒钟都要执行初始化和执行,而我们以useCallback进行包装,就可以将当前函数进行缓存,同时伴随依赖项startTime进行重新初始化。
总结
- useMemo
帮助程序缓存计算结果 - useCallback
帮助程序缓存函数
这些简单的例子让我们简单了解了一下这两个API,以及我们写类组件时候的优化思路如何平移过来,我们接下来会继续介绍其他API。
最后抛出一个问题,在RN项目中,我们的ListEmptyComponent会偶现闪烁的情况,大家猜想一下借助这两个API可以如何优化。