问题
前不久在开发中遇到一个问题,在一个基于class component的react项目,想要使用像hooks里的useEffect
这样的函数,来监听某些props的变化,每当这些props变化时,都要执行一遍指定的函数。
如果是在一个使用hooks的组件里,想要实现这样的效果直接使用useEffect
即可,但是问题就在于目前的这个组件是用class写的,而且组件也很庞大复杂,如果想要用hooks重写,一是时间不允许,二是测试不允许,重写后必须得重新测试(测试同学OS:已经测试过的功能你怎么又让我重测一遍,(╯`□′)╯~ ╧╧,不干!)。
那么摆在面前的问题来了:如何在class组件中使用hooks函数?
首先第一步肯定是先翻看一下官方文档,看一下有没有标准的解决方案,但是很不幸的是:
这就意味着,Hooks不是一个使项目更简洁的小功能,而是React一个完全不同于class组件的全新的核心概念。
既然官方已经明确说了,class组件里hooks函数是不生效的,那么是不是我们的问题就没有解了呢?当然不是,在JavaScript的世界里,一切皆有解决办法。
解决办法
以一个简单的useScreenWidth
hook函数威力,它的目的是获取全屏的宽度,并且去监听浏览器窗口的变化,更新宽度:
import { useEffect, useState } from 'react';
export function useScreenWidth(): number {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handler = (event: any) => {
setWidth(event.target.innerWidth);
};
// 监听浏览器窗口变化
window.addEventListener('resize', handler);
// 组件unmount时要解除监听
return () => {
window.removeEventListener('resize', handler);
};
}, []);
return width;
}
useState
返回两个值:一个是state
状态值,另一个是它的setter
函数。
useEffect
有两个参数:第一个是要执行的函数,第二个是要监听的变量组成的数组。如果监听数组中某一个值发生了变化,那么第一个参数(要执行的函数)就会在下一轮渲染时执行。 第二个参数有三种情况:
- 没有任何参数:
useEffect
在每一次重渲染都会执行 - 空数组
[]
:useEffect
只会在第一次渲染时执行,因为空数组不会有变化 [arg1, arg2, ...]
:数组中任意值发生了变化,useEffect
在下一次渲染都会执行
方法1:将Hook包装成HOC
HOC是React中复用组件的高级用法,它的本质是一个函数,它的输入参数是一个组件,返回相同的组件以及一些额外的props。在我们的例子里,可以让hook函数作为props传递到目标组件中:
import React from 'react';
import { useScreenWidth } from '../hooks/useScreenWidth';
export const withHooksHOC = (Component: any) => {
return (props: any) => {
const screenWidth = useScreenWidth();
return <Component width={screenWidth} {...props} />;
};
};
最后一步就是将我们的目标组件用上述的withHooksHOC
包装起来,那么我们就可以将width
传递给了目标组件:
import React from 'react';
import { withHooksHOC } from './withHooksHOC';
interface IHooksHOCProps {
width: number;
}
class HooksHOC extends React.Component<IHooksHOCProps> {
render() {
return <p>width: {this.props.width}</p>;
}
}
export default withHooksHOC(HooksHOC);
方法2:将Hook包装成函数组件
另外一种方法就是将hook变成函数组件,它接收一个参数为width
的children
函数,然后将width
作为render prop传递:
import { FunctionComponent } from 'react';
import { useScreenWidth } from '../hooks/useScreenWidth';
type ScreenWidthChildren = (screenWidth: number) => React.ReactNode;
interface IScreenWidthProps {
children: ScreenWidthChildren;
}
export const ScreenWidth: FunctionComponent<IScreenWidthProps> = ({
children,
}) => {
const screenWidth: number = useScreenWidth();
return children(screenWidth);
};
使用:
import React from 'react';
import { ScreenWidth } from './ScreenWidth';
export class HooksRenderProps extends React.Component {
render() {
return (
<ScreenWidth>
{(width) => <p style={{ fontSize: '48px' }}>width: {width}</p>}
</ScreenWidth>
);
}
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!