从源码入手探究一个因useImperativeHandle引起的Bug

今天本来正在工位上写着一段很普通的业务代码,将其简化后大致如下:
function App(props: any) {// 父组件const subRef = useRef<any>(null)const [forceUpdate, setForceUpdate] = useState<number>(0)const callRef = () => {subRef.current.sayName() // 调用子组件的方法}const refreshApp = () => { // 模拟父组件刷新的方法setForceUpdate(forceUpdate + 1)}return <div><SubCmp1 refreshApp={refreshApp} callRef={callRef} /><SubCmp2 ref={subRef} /></div>}class SubCmp1 extends React.Component<any, any> { // 子组件1constructor(props: any) {super(props)this.state = {count: 0}}add = () => {this.props.refreshApp()// 会导致父组件重渲染的操作// 修改自身数据,并在回调函数中调用外部方法this.setState({ count: this.state.count + 1 }, () => {this.props.callRef()})}render() {return <div><button onClick={this.add}>Add</button><span>{this.state.count}</span></div>}}const SubCmp2 = forwardRef((props: any, ref) => { // 子组件2useImperativeHandle(ref, () => {return {sayName: () => {console.log('SubCmp2')}}})return <div>SubCmp2</div>})代码结构其实非常简单 , 一个父组件包含有两个子组件 。其中的组件2因为要在父组件中调用它的内部方法 , 所以用forwardRef包裹,并通过useImperativeHandle向外暴露方法 。组件1则是通过props传递了两个父组件的方法,一个是用于间接地访问组件2中的方法,另一个则是可能导致父组件重渲染的方法(当然这种结构的安排明显是不太合理的,但由于项目历史包袱的原因咱就先不考虑这个问题了\doge) 。
然后当我满心欢喜地

    推荐阅读