從源碼入手探究一個因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) 。
然后當我滿心歡喜地

    推薦閱讀