【React】父组件调用子组件方法场景总结

1,285 阅读1分钟

类组件

使用React.createRef()

缺点:如果子组件是嵌套了HOC,就无法指向真实子组件

//outer
import React, { useEffect } from "react";
import Inner from "./Inner";

export default function Outer() {
    const innerRef = React.createRef();
    return (
        <div>
            <p>Outer......</p>
            <Inner ref={innerRef} />
            <button onClick={() => innerRef.current.changeNumber()}>
                    outer-change-number
            </button>
        </div>
    );
}
//inner
import React, { Component } from 'react'

export default class Inner extends Component {
    constructor(props) {
        super(props);
        this.state = {
                number:0
        }
    }
    changeNumber = () => {
        this.setState({number:++this.state.number});
    }
    render() {
        return (
            <div>
                <p>{this.state.number}</p>
                <button onClick={this.changeNumber}>inner-set-number</button>
            </div>
        )
    }
}

使用ref的函数式声明

缺点:如果子组件是嵌套了HOC,就无法指向真实子组件

//outer
import Inner from "./Inner";
import React, { Component } from "react";

export default class Outer extends Component {
    render() {
        return (
            <div>
                <p>Outer......</p>
                <Inner ref={node => this.Inner = node} />
                <button onClick={() => this.Inner.changeNumber()}>
                    outer-change-number
                </button>
            </div>
        );
    }
}
//inner
import React, { Component } from 'react'

export default class Inner extends Component {
    constructor(props) {
        super(props);
        this.state = {
                number:0
        }
    }
    changeNumber = () => {
        this.setState({number:++this.state.number});
    }
    render() {
        return (
            <div>
                <p>{this.state.number}</p>
                <button onClick={this.changeNumber}>inner-set-number</button>
            </div>
        )
    }
}

使用props自定义onRef属性

优点:如果子组件是嵌套了HOC,也可以指向真实子组件 缺点:需要自定义props属性

//outer
import Inner from "./Inner";
import React, { Component } from "react";

export default class Outer extends Component {
    render() {
        return (
            <div>
                <p>Outer......</p>
                <Inner ref={node => this.Inner = node} />
                <button onClick={() => this.Inner.changeNumber()}>
                    outer-change-number
                </button>
            </div>
        );
    }
}
//inner
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'

@withRouter
export default class Inner extends Component {
    constructor(props) {
        super(props);
        this.state = {
                number:0
        }
    }
    changeNumber = () => {
        this.setState({number:++this.state.number});
    }
    componentDidMount(){
        this.props.onRef && this.props.onRef(this);
    }
    render() {
        return (
            <div>
                <p>{this.state.number}</p>
                <button onClick={this.changeNumber}>inner-set-number</button>
            </div>
        )
    }
}

函数组件

使用React.createRef()和useImperativeHandle

//outer
import React from "react";
import Inner from "./Inner";

export default function Outer() {
    const innerRef = React.createRef();
    return (
        <div>
            <p>Outer......</p>
            <Inner onRef={innerRef} />
            <button onClick={() => innerRef.current.changeNumber()}>
                    outer-change-number
            </button>
        </div>
    );
}
//inner
import React, { useImperativeHandle, useState } from "react";

export default function Inner(props) {
    let [number, setNumber] = useState(0);
    const changeNumber = () => {
        setNumber(++number);
    };
    useImperativeHandle(props.onRef, () => {
        return {
                changeNumber,
        };
    });
    return (
        <div>
            <p>{number}</p>
            <button onClick={changeNumber}>inner-set-number</button>
        </div>
    );
}

如果父组件使用ref,则子组件需要使用forwardRef

//outer
import React from "react";
import Inner from "./Inner";

export default function Outer() {
    const innerRef = React.createRef();
    return (
        <div>
            <p>Outer......</p>
            <Inner ref={innerRef} />
            <button onClick={() => innerRef.current.changeNumber()}>
                outer-change-number
            </button>
        </div>
    );
}
//inner
import React, { forwardRef, useImperativeHandle, useState } from "react";

const Inner = forwardRef((props,ref)=>{
    let [number, setNumber] = useState(0);
    const changeNumber = () => {
        setNumber(++number);
    };
    useImperativeHandle(ref, () => {
        return {
                changeNumber,
        };
    });
    return (
        <div>
            <p>{number}</p>
            <button onClick={changeNumber}>inner-set-number</button>
        </div>
    );
})

export default Inner;

总结

  • 类组件推荐使用props自定义onRef属性,无论组件嵌套多少层HOC,均能获取到
  • 函数组件使用React.createRef()和useImperativeHandle