【问题标题】:Call child function from parent component in React Native从 React Native 中的父组件调用子函数
【发布时间】:2017-03-11 11:53:39
【问题描述】:

我正在开发我的第一个 React Native 应用程序。我想要实现的是从父组件执行子函数,这是这种情况:

儿童

export default class Child extends Component {
  ...
  myfunct: function() {
    console.log('Managed!');
  }
  ...
  render(){
    return(
      <Listview
      ...
      />
    );
  }
}

家长

export default class Parent extends Component {
  ...
  execChildFunct: function() {
    ...
    //launch child function "myfunct"
    ...
    //do other stuff
  }

  render(){
    return(
      <View>
        <Button onPress={this.execChildFunct} />
        <Child {...this.props} />
      </View>);
  }
}

在这个例子中,当我按下父类中的按钮时,我想记录'Managed!'。怎么可能?

【问题讨论】:

    标签: react-native


    【解决方案1】:

    Nader Dabit 的答案已经过时,因为在 ref 属性 has been deprecated 中使用字符串文字。从 2017 年 9 月起,我们就是这样做的:

    <Child ref={child => {this.child = child}} {...this.props} />
    <Button onPress={this.child.myfunc} />
    

    相同的功能,但不是使用字符串来引用组件,而是将其存储在全局变量中。

    【讨论】:

    • 我要谢谢你,我不知道为什么这个答案不被接受,这是现在的方法。我现在正在学习 react native,所以代码有点混乱。我不得不对其进行一些更改以使其也能正常工作。 { this.child = child; }}/> 并调用它使用 this.child.functionName
    【解决方案2】:

    你可以给子组件添加一个 ref:

    <Child ref='child' {...this.props} />
    

    然后像这样调用孩子的方法:

    <Button onPress={this.refs.child.myfunc} />
    

    【讨论】:

    • 但是execChildFunct 还必须做其他事情:我可以在execChildFunct 中调用this.refs.child.myfunct 吗?因为我试过但没有用:/
    • 如何设置 ref 为this.props.children ??
    【解决方案3】:

    以下是使用功能组件执行此操作的方法:

    家长

    1. 使用useRef() 给子组件在父组件中的引用:
    const childRef = useRef()
    // ...
    return (
       <ChildComponent ref={childRef} />
    )
    ...
    

    儿童

    1. ref 作为构造函数参数之一传递:
    const ChildComponent = (props, ref) => {
      // ...
    }
    
    1. 'react' 库中导入useImperativeHandleforwardRef 方法:
    import React, { useImperativeHandle, forwardRef } from 'react'
    
    1. 使用useImperativeHandle 将函数绑定到ref 对象,这将使父对象可以访问这些函数

    这些方法在内部不可用,因此您可能希望使用它们来调用内部方法。

    const ChildComponent = (props, ref) => {
      //...
      useImperativeHandle(ref, () => ({
        // each key is connected to `ref` as a method name
        // they can execute code directly, or call a local method
        method1: () => { localMethod1() },
        method2: () => { console.log("Remote method 2 executed") }
      }))
      //...
      
      // These are local methods, they are not seen by `ref`,
      const localMethod1 = () => {
        console.log("Method 1 executed")
      }
      // ..
    }
    
    1. 使用forwardRef导出子组件:
    const ChildComponent = (props, ref) => {
      // ...
    }
    export default forwardRef(ChildComponent)
    

    把它们放在一起

    子组件

    import React, { useImperativeHandle, forwardRef } from 'react';
    import { View } from 'react-native'
    
    
    const ChildComponent = (props, ref) => {
      useImperativeHandle(ref, () => ({
        // methods connected to `ref`
        sayHi: () => { sayHi() }
      }))
      // internal method
      const sayHi = () => {
        console.log("Hello")
      }
      return (
        <View />
      );
    }
    
    export default forwardRef(ChildComponent)
    
    

    父组件

    import React, { useRef } from 'react';
    import { Button, View } from 'react-native';
    import ChildComponent from './components/ChildComponent';
    
    const App = () => {
      const childRef = useRef()
      return (
        <View>
          <ChildComponent ref={childRef} />
          <Button
            onPress={() => {
              childRef.current.sayHi()
            }}
            title="Execute Child Method"
          />
        </View>
      )
    }
    
    export default App
    

    Expo Snacks 上有一个互动演示: https://snack.expo.dev/@backupbrain/calling-functions-from-other-components

    这个解释是从这个TutorialsPoint article修改的

    【讨论】:

    • 它说 TypeError: undefined is not an object
    【解决方案4】:

    它正在反应。我希望它可以帮助你。

    class Child extends React.Component {
      componentDidMount() {
        this.props.onRef(this)
      }
      componentWillUnmount() {
        this.props.onRef(null)
      }
      method() {
        console.log('do stuff')
      }
      render() {
        return <h1>Hello World!</h1>
      }
    }
    

    class EnhancedChild extends React.Component {
            render() {
            return <Child {...this.props} />
          }
        }
    
    class Parent extends React.Component {
      onClick = () => {
        this.child.method() // do stuff
      };
      render() {
        return (
          <div>
            <EnhancedChild onRef={ref => (this.child = ref)} />
            <button onClick={this.onClick}>Child.method()</button>
          </div>
        );
      }
    }
    
    ReactDOM.render(<Parent />, document.getElementById('root'))
    

    原解决方案:

    https://jsfiddle.net/frenzzy/z9c46qtv/

    https://github.com/kriasoft/react-starter-kit/issues/909

    【讨论】:

      【解决方案5】:

      简单易行的Parent方法-->子函数调用

      /* Parent.js */
      import React, { Component } from "react";
      import { TouchableOpacity, Text } from "react-native";
      import Child from "./Child";
      
      class Parent extends React.Component {
        onChildClick = () => {
          this.child.childFunction(); // do stuff
        };
        render() {
          return (
            <div>
              <Child onRef={(ref) => (this.child = ref)} />
              <TouchableOpacity onClick={this.onChildClick}>
                <Text>Child</Text>
              </TouchableOpacity>
            </div>
          );
        }
      }
      
      /* Child.js */
      import React, { Component } from "react";
      
      class Child extends React.Component {
        componentDidMount() {
          this.props.onRef(this);
        }
        componentWillUnmount() {
          this.props.onRef(undefined);
        }
        childFunction() {
          // do stuff
          alert("childFunction called");
        }
        render() {
          return <View>Hello World!</View>;
        }
      }
      

      原解决方案: https://github.com/kriasoft/react-starter-kit/issues/909

      【讨论】:

        【解决方案6】:

        我认为您对组件结构有误解。

        假设您的孩子是一个为您的其他组件生成按钮的组件。在这个层次结构中,你的孩子必须通知它的父母它被按下了。

        孩子 -----> 父母

        export default class Child extends Component {
        
             return(
            <Button onPress={this.props.onPress } />
             );
          }
        

        在您的父组件中使用子组件为您生成一个按钮。这样就可以将子组件用作任何其他组件的独立按钮。

        export default class Parent extends Component {
        constructor(props) {
            super(props);
            this.execChildFunct=this.execChildFunct.bind(this)
          }
        
          execChildFunct: function() {
          console.log('Managed!');
          }
          return (
           <Child onPress = {this.execChildFunct}></Child>
          )
        
        }
        

        【讨论】:

        • 感谢您的回答布拉克!我已经改进了对问题的解释,抱歉不清楚:我知道你在说什么,我想做的是不同的。这两个函数(子函数和父函数)还可以做其他事情,为了更清楚,我已经简化了。有没有办法直接访问子组件的功能?
        • bind 的用途是什么?虽然 child onPress 已经使用this,但这意味着调用它的方法 (execChildFunct) 。为什么我们需要bind 这个功能?
        • @TomSawyer 为了在 execChildFunct 中使用实例变量,必须绑定函数。在这种情况下,我只需登录该功能。所以绑定不是强制性的。
        • @BurakKarasoy 那么,这意味着如果我们在execChildFunct 中使用this => this 指的是Child 实例?此处使用绑定的目的是创建名为 Child.execChildFunct = Parent.execChildFunct? 的函数
        • @TomSawyer 我不明白你的意思。假设这个类有状态,为了在这个函数中达到这些状态,你需要绑定它。此外,例如,如果您在构造函数中声明 this.elementX 之类的变量。你必须绑定函数才能到达这个元素。
        猜你喜欢
        • 2016-09-07
        • 2020-11-02
        • 2020-02-27
        • 2016-12-03
        • 1970-01-01
        • 1970-01-01
        • 2015-11-09
        • 2020-02-15
        • 2020-03-28
        相关资源
        最近更新 更多