如何访问子级中父级组件的引用

时间:2018-12-17 07:46:42

标签: javascript reactjs react-native

我有一个父母和一个孩子,我必须确保父亲中包含的孩子部分可以引用他。

例如,在子按钮上,我要调用父控件中使用的openDrawer()方法。

我试图通过道具将父母对孩子的引用传递给孩子,但这不起作用。

我在哪里做错了?

我该怎么办?

父母:

import * as React from 'react';
import { StyleSheet, View, Text, ToastAndroid, Button, Toolbar } from 'react-native';
import NavigationDrawerLayout from 'react-native-navigation-drawer-layout';

import Homepage from './page/Homepage';
import PageOne from './page/pageOne';
import PageTwo from './page/pageTwo';

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      menu: '',
      type: '',
      drawer: ''
    };
  }

  render() {
    return (
      <NavigationDrawerLayout
        ref={_drawer => (this.drawer = _drawer)}
        //ref={(_drawer) => this.setState({drawer:_drawer})}
        percent={75}
        //statusBar="#008cff"
        //statusBarTransparency={0.3}
        type={this.state.type}
        drawerPosition="left"
        selected="opt3"
        window="menu"
        color="#fff"
        backgroundColor="#303030" //303030
        imageBackground="https://c.wallhere.com/photos/aa/44/glare_colorful_bright_circles-679384.jpg!d"
        first={'username'}
        second={'joined'}
        account={[
          {
            username: 'james.bond',
            name: 'James Bond',
            email: 'james.bond.xx@xxx.xxx',
            image:
              'https://cdn1.iconfinder.com/data/icons/avatar-2-2/512/Casual_Man_2-512.png',
            joined: 'Joined at Jun 21, 2021',
            badgeText: '100',
            badgeColor: '#fff',
            badgeBackground: '#303030',
            circle: ['transparent', 'transparent'],
          },
          {
            username: 'sherlock.holmes',
            name: 'Sherlock Holmes',
            email: 'sherlock.holmes.xx@xxx.xxx',
            badgeText: '100',
            badgeColor: '#fff',
            badgeBackground: '#303030',
            circle: ['#fff000', 'transparent', '#00ffd0'],
          },
          {
            name: 'Shinichi Kudo',
            email: 'shinichi.kudo.xx@xxx.xxx',
            image:
              'https://cdn1.iconfinder.com/data/icons/avatar-2-2/512/Casual_Man_3-512.png',
            badgeText: '21',
            badgeColor: '#fff',
            badgeBackground: '#25dbd2',
            joined: 'Joined at Jun 31, 2021',
            circle: ['transparent', 'transparent'],
          },
          {
            name: 'Arthur Conan Doyle',
            email: 'arthur.conan.doyle.xx@xxx.xxx',
            image:
              'https://cdn0.iconfinder.com/data/icons/user-interface-vol-3-12/66/68-512.png',
            circle: ['transparent', 'transparent'],
          },
        ]}
        badgeFunction={e => {
          return e > 99 ? '99+' : e;
        }}
        menu={[
          {
            type: 'menu',
            name: 'opt0',
            backgroundLarge: 'transparent',
            backgroundLargeFocus: 'transparent',
            backgroundSmall: 'rgba(13, 71, 161, 0.5)',
            backgroundSmallFocus: 'rgba(213, 0, 0, 0.5)',
            iconLeft: 'apps',
            iconLeftColor: '#c1c1c1',
            iconLeftColorFocus: '#4CAF50',
            title: 'Le mie app e i miei giochi',
            titleColor: '#000000',
            titleColorFocus: '#4CAF50',
            badgeText: '100',
            badgeColor: '#ffffff',
            badgeBackground: '#1194ff',
            iconRight: 'exit-to-app',
            iconRightColor: '#4CAF50',
            iconRightColorFocus: '#EF6C00',
            close: false,
          },
          {
            type: 'menu',
            name: 'opt3',
            title: 'Abbonamenti',
            backgroundLarge: '#4286f4',
            backgroundLargeFocus: '#34ed6b',
            backgroundSmallFocus: 'rgba(213, 0, 0, 0.5)',
            iconLeft: 'apps',
            iconLeftColor: '#c1c1c1',
            iconLeftColorFocus: '#4CAF50',
            badgeText: '100',
            badgeColor: '#ffffff',
            badgeBackground: '#1194ff',
            iconRight: 'exit-to-app',
            iconRightColor: '#4CAF50',
            iconRightColorFocus: '#EF6C00',
          },
        ]}
        onPress={e => {
          ToastAndroid.show("Title: "+e.title+" * "+"Name: "+e.name,ToastAndroid.SHORT);
          console.log('Menu:', e);
          var type = e.name == 'opt2' ? 'simple' : '';
          this.setState({ menu: e.title, type });
        }}>
        <Homepage drawer={this.drawer} />
      </NavigationDrawerLayout>
    );
  }
}

const styles = StyleSheet.create({});

孩子:

import * as React from 'react';
import { Text, View, Button } from 'react-native';

export default class Homepage extends React.Component {
  render() {
    const {drawer} = this.props;
    return (
      <View
        style={{
          flex: 1,
          //alignItems: 'flex-end',
        }}>
        <Text style={{ marginTop: 25, marginRight: 5, textAlign: 'right' }}>Hello World!</Text>
        <Text style={{ marginTop: 25, marginRight: 5, textAlign: 'right' }}>
          State: !
        </Text>
        <Button
          onPress={()=drawer.openDrawer()}
          title="Open"
          color="#4286f4"
        />
      </View>
    );
  }
}

2 个答案:

答案 0 :(得分:0)

通常,孩子不应该认识父母。在这种情况下,传递的不是父(App)引用,而是App的另一个子引用this.drawer

这里的问题是使用了不推荐的ref函数ref={_drawer => (this.drawer = _drawer)}。这会导致竞争状态,因为this.drawer在分配给引用之前已传递给Homepage,所以它是未定义的。

应该是:

this.drawerRef = React.createRef();
...

<NavigationDrawerLayout ref={this.drawerRef} .../>
...
<Homepage drawerRef={this.drawerRef} />

一旦安装NavigationDrawerLayoutdrawerRef.current就被分配了一个实例,并且可以使用:

<Button onPress={()=drawerRef.current.openDrawer()} />

通过ref会破坏封装并在可能避免的地方提供紧密的耦合。 Homepage确实不需要访问整个抽屉。这通常在React中通过传递函数prop来解决:

<Homepage openDrawer={() => this.drawerRef.current.openDrawer()} />

答案 1 :(得分:0)

解决方案1 ​​

您可以将相关方法直接传递给您的孩子。我喜欢这个。

import * as React from 'react';
import { StyleSheet, View, Text, ToastAndroid, Button, Toolbar } from 'react-native';
import NavigationDrawerLayout from 'react-native-navigation-drawer-layout';

import Homepage from './page/Homepage';
import PageOne from './page/pageOne';
import PageTwo from './page/pageTwo';

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      menu: '',
      type: '',
      drawer: ''
    };
    this.openDrawer = this.openDrawer.bind(this);
  }

  openDrawer() {
    // ...
  }

  render() {
    return (
      <NavigationDrawerLayout
        ref={_drawer => (this.drawer = _drawer)}
        //ref={(_drawer) => this.setState({drawer:_drawer})}
        percent={75}
        //statusBar="#008cff"
        //statusBarTransparency={0.3}
        type={this.state.type}
        drawerPosition="left"
        selected="opt3"
        window="menu"
        color="#fff"
        backgroundColor="#303030" //303030
        imageBackground="https://c.wallhere.com/photos/aa/44/glare_colorful_bright_circles-679384.jpg!d"
        first={'username'}
        second={'joined'}
        account={[
          {
            username: 'james.bond',
            name: 'James Bond',
            email: 'james.bond.xx@xxx.xxx',
            image:
              'https://cdn1.iconfinder.com/data/icons/avatar-2-2/512/Casual_Man_2-512.png',
            joined: 'Joined at Jun 21, 2021',
            badgeText: '100',
            badgeColor: '#fff',
            badgeBackground: '#303030',
            circle: ['transparent', 'transparent'],
          },
          {
            username: 'sherlock.holmes',
            name: 'Sherlock Holmes',
            email: 'sherlock.holmes.xx@xxx.xxx',
            badgeText: '100',
            badgeColor: '#fff',
            badgeBackground: '#303030',
            circle: ['#fff000', 'transparent', '#00ffd0'],
          },
          {
            name: 'Shinichi Kudo',
            email: 'shinichi.kudo.xx@xxx.xxx',
            image:
              'https://cdn1.iconfinder.com/data/icons/avatar-2-2/512/Casual_Man_3-512.png',
            badgeText: '21',
            badgeColor: '#fff',
            badgeBackground: '#25dbd2',
            joined: 'Joined at Jun 31, 2021',
            circle: ['transparent', 'transparent'],
          },
          {
            name: 'Arthur Conan Doyle',
            email: 'arthur.conan.doyle.xx@xxx.xxx',
            image:
              'https://cdn0.iconfinder.com/data/icons/user-interface-vol-3-12/66/68-512.png',
            circle: ['transparent', 'transparent'],
          },
        ]}
        badgeFunction={e => {
          return e > 99 ? '99+' : e;
        }}
        menu={[
          {
            type: 'menu',
            name: 'opt0',
            backgroundLarge: 'transparent',
            backgroundLargeFocus: 'transparent',
            backgroundSmall: 'rgba(13, 71, 161, 0.5)',
            backgroundSmallFocus: 'rgba(213, 0, 0, 0.5)',
            iconLeft: 'apps',
            iconLeftColor: '#c1c1c1',
            iconLeftColorFocus: '#4CAF50',
            title: 'Le mie app e i miei giochi',
            titleColor: '#000000',
            titleColorFocus: '#4CAF50',
            badgeText: '100',
            badgeColor: '#ffffff',
            badgeBackground: '#1194ff',
            iconRight: 'exit-to-app',
            iconRightColor: '#4CAF50',
            iconRightColorFocus: '#EF6C00',
            close: false,
          },
          {
            type: 'menu',
            name: 'opt3',
            title: 'Abbonamenti',
            backgroundLarge: '#4286f4',
            backgroundLargeFocus: '#34ed6b',
            backgroundSmallFocus: 'rgba(213, 0, 0, 0.5)',
            iconLeft: 'apps',
            iconLeftColor: '#c1c1c1',
            iconLeftColorFocus: '#4CAF50',
            badgeText: '100',
            badgeColor: '#ffffff',
            badgeBackground: '#1194ff',
            iconRight: 'exit-to-app',
            iconRightColor: '#4CAF50',
            iconRightColorFocus: '#EF6C00',
          },
        ]}
        onPress={e => {
          ToastAndroid.show("Title: "+e.title+" * "+"Name: "+e.name,ToastAndroid.SHORT);
          console.log('Menu:', e);
          var type = e.name == 'opt2' ? 'simple' : '';
          this.setState({ menu: e.title, type });
        }}>
        <Homepage openDrawer={this.openDrawer} />
      </NavigationDrawerLayout>
    );
  }
}

const styles = StyleSheet.create({});

解决方案2

您可以直接使用React.createRef()

URL:https://reactjs.org/docs/refs-and-the-dom.html

import * as React from 'react';
import { StyleSheet, View, Text, ToastAndroid, Button, Toolbar } from 'react-native';
import NavigationDrawerLayout from 'react-native-navigation-drawer-layout';

import Homepage from './page/Homepage';
import PageOne from './page/pageOne';
import PageTwo from './page/pageTwo';

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      menu: '',
      type: '',
      drawer: ''
    };
    this.myRef = React.createRef();
  }

  render() {
    return (
      <NavigationDrawerLayout
        ref={this.myRef}
        //ref={(_drawer) => this.setState({drawer:_drawer})}
        percent={75}
        //statusBar="#008cff"
        //statusBarTransparency={0.3}
        type={this.state.type}
        drawerPosition="left"
        selected="opt3"
        window="menu"
        color="#fff"
        backgroundColor="#303030" //303030
        imageBackground="https://c.wallhere.com/photos/aa/44/glare_colorful_bright_circles-679384.jpg!d"
        first={'username'}
        second={'joined'}
        account={[
          {
            username: 'james.bond',
            name: 'James Bond',
            email: 'james.bond.xx@xxx.xxx',
            image:
              'https://cdn1.iconfinder.com/data/icons/avatar-2-2/512/Casual_Man_2-512.png',
            joined: 'Joined at Jun 21, 2021',
            badgeText: '100',
            badgeColor: '#fff',
            badgeBackground: '#303030',
            circle: ['transparent', 'transparent'],
          },
          {
            username: 'sherlock.holmes',
            name: 'Sherlock Holmes',
            email: 'sherlock.holmes.xx@xxx.xxx',
            badgeText: '100',
            badgeColor: '#fff',
            badgeBackground: '#303030',
            circle: ['#fff000', 'transparent', '#00ffd0'],
          },
          {
            name: 'Shinichi Kudo',
            email: 'shinichi.kudo.xx@xxx.xxx',
            image:
              'https://cdn1.iconfinder.com/data/icons/avatar-2-2/512/Casual_Man_3-512.png',
            badgeText: '21',
            badgeColor: '#fff',
            badgeBackground: '#25dbd2',
            joined: 'Joined at Jun 31, 2021',
            circle: ['transparent', 'transparent'],
          },
          {
            name: 'Arthur Conan Doyle',
            email: 'arthur.conan.doyle.xx@xxx.xxx',
            image:
              'https://cdn0.iconfinder.com/data/icons/user-interface-vol-3-12/66/68-512.png',
            circle: ['transparent', 'transparent'],
          },
        ]}
        badgeFunction={e => {
          return e > 99 ? '99+' : e;
        }}
        menu={[
          {
            type: 'menu',
            name: 'opt0',
            backgroundLarge: 'transparent',
            backgroundLargeFocus: 'transparent',
            backgroundSmall: 'rgba(13, 71, 161, 0.5)',
            backgroundSmallFocus: 'rgba(213, 0, 0, 0.5)',
            iconLeft: 'apps',
            iconLeftColor: '#c1c1c1',
            iconLeftColorFocus: '#4CAF50',
            title: 'Le mie app e i miei giochi',
            titleColor: '#000000',
            titleColorFocus: '#4CAF50',
            badgeText: '100',
            badgeColor: '#ffffff',
            badgeBackground: '#1194ff',
            iconRight: 'exit-to-app',
            iconRightColor: '#4CAF50',
            iconRightColorFocus: '#EF6C00',
            close: false,
          },
          {
            type: 'menu',
            name: 'opt3',
            title: 'Abbonamenti',
            backgroundLarge: '#4286f4',
            backgroundLargeFocus: '#34ed6b',
            backgroundSmallFocus: 'rgba(213, 0, 0, 0.5)',
            iconLeft: 'apps',
            iconLeftColor: '#c1c1c1',
            iconLeftColorFocus: '#4CAF50',
            badgeText: '100',
            badgeColor: '#ffffff',
            badgeBackground: '#1194ff',
            iconRight: 'exit-to-app',
            iconRightColor: '#4CAF50',
            iconRightColorFocus: '#EF6C00',
          },
        ]}
        onPress={e => {
          ToastAndroid.show("Title: "+e.title+" * "+"Name: "+e.name,ToastAndroid.SHORT);
          console.log('Menu:', e);
          var type = e.name == 'opt2' ? 'simple' : '';
          this.setState({ menu: e.title, type });
        }}>
        <Homepage drawer={this.myRef.current} />
      </NavigationDrawerLayout>
    );
  }
}

const styles = StyleSheet.create({});