灵感来源来自一个面试官问我为什么hook函数不能在class类组件中使用?如何在class类组件中使用呢?
第一个问题你们自己可以百度一下晚上有,今天着重讲解一下第二个问题。
碰到这个问题首先要进行分析:
(1)hook函数在什么情况下可以调用?答:函数最外层可以调用Hook。
=>可不可以衍生一个函数代替class类组件调用?答:高阶组件就可以,因为高阶组件本身就是从高阶函数演变过来,高阶函数我的理解就是在高阶函数内调用传过来的参数(参数一般为回调函数)。高阶组件概念差不多,只不过,参数为组件,在react中组件的本质就是函数。。。
接下来,那么我们现在实现一个需求——————来个数字递增效果,然后到达某一个值时,停止。
原先错误的代码是这样的:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="root"></div>
<script src="https://cdn.bootcss.com/react/16.8.6/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.8.6/umd/react-dom.development.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"></script>
<script type="text/babel">
const useState = React.useState;
function useDateHook(){
return new Date().toDateString()
}
let timer = null;
function withHooksHOC(Component){
return function (props){
const nowDate = useDateHook();
let [date,setDate] = useState(5);
timer = setInterval(()=>{
date++;
setDate(date)
/*if(date == 10){ //错误1
clearInterval(timer)
}*/
},1000)
if(date == 10){//错误2
console.log("exe")
clearInterval(timer)
}
return <Component date={date}
{...props} />;
}
}
class DateCom extends React.Component{
render() {
return <p>date: {this.props.date}</p>;
}
}
let WithHooksHOCer = withHooksHOC(DateCom);
class App extends React.Component{
constructor(props){
super(props)
}
render() {
return <WithHooksHOCer />;
}
};
ReactDOM.render(<App />,document.querySelector('#root'))
</script>
</body>
</html>
错误1和错误2其实错误点都差不多,都是date到达10的时候清掉当前定时器,但是每次HOOK setState函数每次更新数据都会生成一个定时器,慢慢的越来越多,导致页面崩溃!
在之前科普一下useRef作用?
1.获取DOM对象
2.保存数据
useRef相当于在函数式组件中添加了一个实例对象。useRef不会因为组件的更新而丢失数据,虽然组件进行了更新,但是通过useRef保存的数据并不随之发生改变。
3.ref对象的值发生改变之后,不会触发组件重新渲染。
(https://blog.csdn.net/qq_30267753/article/details/125173931)
下面是解决方案,这里用到了自定义hook函数,然后借鉴useEffect函数结合高阶函数(传递函数作为参数)和useRef作用(声明全局变量)的形式,并配置useEffect第二个参数,数组为空代表,组件挂载后和卸载后执行,[参数]表明,参数变化时,这点刚好契合定时函数定时传参的效果!即每次调用自定义hook函数的时候初始化生成一个回调函数的镜像,然后再另外一个副作用函数里代替执行回调函数内容,相当于直接在自定义hook函数中执行定时器效果。
下面是正确的完整的代码,可以在浏览器跑
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="root"></div>
<script src="https://cdn.bootcss.com/react/16.8.6/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.8.6/umd/react-dom.development.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"></script>
<script type="text/babel">
const useState = React.useState;
const useEffect = React.useEffect;
const useRef = React.useRef;
function useDateHook() {
return new Date().toDateString()
}
function withHooksHOC(Component) {
return function (props) {
const nowDate = useDateHook();
let [date, setDate] = useState(5);
useInterval(() => {
if(date < 10){
setDate(date + 1);
}
}, 1000)
props = {
date,
nowDate
}
return <Component {...props} />
}
}
function useInterval(callback,delay){
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback; //每次都初始化一个saveCallBack对象 用于后面副作用函数执行。
}, [callback]); //第二个参数代表callback每次变化就就行,数组为空就代表组件挂载和卸载的时候执行
useEffect(() => {
let id = setInterval(() => {
savedCallback.current(); //执行回调
}, delay);
return function (){
clearInterval(id);
}
}, [delay])
}
class DateCom extends React.Component {
render() {
return <div id="box"><p>date: {this.props.date}</p><p>props:{this.props.nowDate}</p></div>
}
}
let WithHooksHOCer = withHooksHOC(DateCom);
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
return <WithHooksHOCer />;
}
};
ReactDOM.render(<App />, document.querySelector('#root'))
</script>
</body>
</html>
参考文献:
https://www.52dianzi.com/category/article/37/689191.html。
https://baijiahao.baidu.com/s?id=1744203108622010543&wfr=spid...。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。