如何从父类访问子组件的状态

时间:2020-07-31 10:20:17

标签: reactjs ionic-framework

儿童班:

interface Props {
    name: string;
    mac: string;
}

export const BluetoothDeviceItem = (Props, { }) => {
    const [connectingState, setConnectingState] = useState('not_connected');
    useEffect(() => {
        stateChangeCallback();
    }, [connectingState]);

    const { onClick } = Props;

    const stateChangeCallback = () => {
        switch (connectingState) {
            case 'not_connected':
                console.log("not_connected!");
                break;
            case 'connecting':
                console.log("connecting!");
                break;
            case 'connected':
                console.log("connected!");
                break;
        }
    }

    const wait = async () => {
        setConnectingState('connecting');

        let ret = await onClick(Props.mac);
    }

    return (
        <IonItem lines="none" class="item-container" onClick={wait} id={Props.mac} >
        </IonItem>
    );
}

“父级”类(从技术上讲,不是父级,因为元素在不同的类中呈现)

class Bluetooth extends React.Component<{}, {}}> {
    scan() {
        for(let i = 0; i < 5; i++) { //using a for loop to pretend bluetooth devices are being found
            let a = <BluetoothDeviceItem key={i} mac={i.toString()} name={"device_"+i} onClick={this.connect}></BluetoothDeviceItem>
        
            bluetoothDevices.push(a); //bluetoothDevices is a *global*
        }  
    }
  
    connect = (id) => {
        bluetoothDevices.forEach(element => {
            //access the state of each element
        });
    }
}

我首先发布了我的代码,以使其更容易解释。

我有两节课。一个是子类(BlueoothDeviceItem)。在这个类中,有一个状态。它可以具有3个值not_connectedconnectingconnected。这段代码被简化了,但是这些状态将会更改某些图标和颜色。

然后是“父”类。这与蓝牙代码有关。正如我在评论中提到的那样,我使用for循环假装找到设备。这大大简化了代码。
调用scan时,每次找到设备时,都会使用名称和MAC地址创建一个新子级(BluetoothDeviceItem)。这些设备中的每一个将默认为未连接。 当您单击一个时,它将使用单击事件来调用父级函数(connect)。 我相信蓝牙代码的最佳实践是自己做所有事情。这包括断开设备连接等,以免依赖设备断开连接(至少根据文档,对于某些部件,这是一种好习惯)。蓝牙一次仅允许1个连接。这当然意味着当用户尝试连接一个蓝牙设备时,我需要断开当前连接的所有蓝牙设备。
由于我的孩子班级有3个州,所以我认为这些将是最好的用法。当用户连接到设备时,我会遍历所有设备。如果状态为connectingconnected,请断开这些设备的连接。
但是,问题在于您无法访问状态,因为它们是该类的私有状态。我也尝试过道具,但道具是只读的,因此我将无法对其进行修改。 我尝试的最后一件事是refs

class Bluetooth extends React.Component<{}, {}> {
    ref: any;

    constructor({}) {
        super({});

        this.ref = React.createRef();
    }

    scan() {
        for(let i = 0; i < 5; i++) { //using a for loop to pretend bluetooth devices are being found
            let a = <BluetoothDeviceItem key={i} mac={i.toString()} name={"device_"+i} onClick={this.connect} elRef={this.ref}></BluetoothDeviceItem>
        
            bluetoothDevices.push(a); //bluetoothDevices is a *global*
        }  
    }
  
    connect = (id) => {
        bluetoothDevices.forEach(element => {
            this.ref.current.state //doesn't work since it's a DOM element.
            this.ref.current.getState() //also doesnt work
        });
    }
}

同时还将界面更改为:

interface Props {
    name: string;
    mac: string;
    elRef: any;
}

和IonItem可以:

<IonItem lines="none" class="item-container" onClick={wait} id={Props.mac} ref={Props.elRef} >

由于它是DOM元素,所以不能使用this.ref.current.state。我尝试的最后一件事是:

<IonItem lines="none" class="item-container" onClick={wait} id={Props.mac} ref={Props.elRef} key={Props.mac} {...{"getState": () => console.log(connectingState)}}>

创建一个getter函数以返回状态。这是最接近我需要的状态,它确实返回了状态,但是它依赖于 all 处于相同状态的所有设备进行更改。即如果任何一个设备的状态为not_connected,则该函数将返回not_connected。一旦所有设备的状态为connecting

,它只会返回connecting

2 个答案:

答案 0 :(得分:1)

您可以在父组件中维护所有子状态。那也将为您简化事情。使用父类中定义的方法将状态传递给事件并处理事件,作为对孩子的支持。

答案 1 :(得分:0)

在React中,当我们必须将数据从父级传递到子级时,我们只是通过props,但是当我们需要在Parent中访问Child的数据时,我们使用回调函数来实现。该函数是在Parent中定义的,它像您一样接受参数。

  connect = (id) => {
    bluetoothDevices.forEach(element => {
        //access the state of each element
    });
  }

我们在道具中将此回调函数传递给child,而Child则回调该函数以提供像这样的道具。

const { onClick } = Props;
<BluetoothDeviceItem onClick={() => onClick(id)} />

在Child中调用回调并传递参数时。请记住要用作箭头函数,因为否则它将不会接受您想要传递给父级的参数。您的情况是id是参数。