之前遇到过的一个需求,子组件的倒计时按钮需要让父组件控制是否调用或停止,记录下。
如果要将子组件暴露给父组件,我们要用到react中的forwardRef以及useImperativeHandle这两个API
import React, { useImperativeHandle, forwardRef, useState, useEffect } from 'react';
// 计时器 必须声明在组件外部 在内部会一直循环
let timeChange;
const ChildrenModel = forwardRef((props, ref) => {
// 按钮计时
const [time, setTime] = useState(60);
// 按钮状态
const [btnState, setBtnState] = useState(false);
// 通过useImperativeHandle将自身方法暴露给父级
useImperativeHandle(ref, () => ({
start
}))
// 开始计时
const start = () => {
// 避免计时重复 先清除
clearInterval(timeChange);
// 使用--t t-1会闭包
timeChange = setInterval(() => setTime(t => --t), 1000);
// 当计时开始 按钮状态为不可点击
setBtnState(true);
}
// 组件注销时,移除计时器
useEffect(() => {
return () => clearInterval(timeChange);
}, [])
useEffect(() => {
// 监听计时结束 清除计时器 重新赋值 恢复按钮
if (time <= 0) {
clearInterval(timeChange);
setTime(60);
setBtnState(false);
}
}, [time])
return (
<div>
<h1>将方法暴露给父组件</h1>
<button
disabled={btnState}
style={{ height: "36px", width: "200px", textAlign: "center", display: "block", margin: "0 auto" }}
>{time === 60 ? "点击倒计时" : `${time}秒后点击`}</button>
</div>
)
})
子组件写好,接下来就是父组件直接调用就可以了
import React, {useRef, useState } from 'react';
import ChildrenModel from './Children/Children';
export default function Section() {
// 子组件绑定Ref
const childRef = useRef();
// 点击父组件 调用子组件方法
const childMethod = () => {
// 通过子组件绑定的ref 来操作方法
childRef.current.start();
}
return (
<div className='main'>
<button onClick={childMethod}>父组件按钮</button>
<ChildrenModel ref={childRef}></ChildrenModel>
</div>
)
}
OKOKOK!