【问题标题】:Unable to access child function via ref?无法通过 ref 访问子功能?
【发布时间】:2017-02-03 13:28:01
【问题描述】:

最初一切正常,我有一个类似的组件。 这个

  class A extends React.Component {
     constructor(props) {
       super(props);
       this.childRef = null
     }

    componentDidMount() {
     this.childRef = this.refs.b
     // now I can call child function like this
      this.childRef.calledByParent()
    }

    render(){
      <B ref = "b"/>
    }
  }

在其他文件中

     class B extends React.Component {

       calledByParent(){
         console.log("i'm called")
        }

       render(){
        <div> hello </div>
       }
  }
 export default B

到这里它工作正常但是当我在class Bexport default connect(mapStateToProps, mapDispatchToProps)(B)做这样的事情时

它不工作。我已经从 react-redux 导入了连接

【问题讨论】:

  • 有意义,因为connect 将另一个组件包裹在父组件周围。那么,问题是什么?

标签: reactjs redux react-redux


【解决方案1】:

connect() 接受 option 作为第四个参数。在此选项参数中,您可以将标志 withRef 设置为 true。在此之后,您可以使用getWrappedInstance() like 访问引用函数

class A extends React.Component {
     constructor(props) {
       super(props);
       this.childRef = null
     }

    componentDidMount() {
        this.childRef.getWrappedInstance().calledByParent()
    }

    render(){
      <B ref = {ref => this.childRef = ref}/>
    }
  }

class B extends React.Component {

       calledByParent(){
         console.log("i'm called")
        }

       render(){
        <div> hello </div>
       }
  }
   export default  connect(mapStateToProps, mapDispatchToProps, null, {withRef: true})(B)

【讨论】:

    【解决方案2】:

    可能有点晚了,但比使用 refs 的另一个(更好的)解决方案是只控制组件的特定功能。

    class A extends React.Component {
        constructor(props) {
            super(props);
        }
    
        componentDidMount() {
            this.ctrl_B.calledByParent()
        }
    
        render(){
            <B provideCtrl={ctrl => this.ctrl_B = ctrl} />
        }
    }
    
    class B extends React.Component {
    
        componentDidMount() {
            this.props.provideCtrl({
                calledByParent: () => this.calledByParent()
            });
        }
        componentWillUnmount() {
            this.props.provideCtrl(null);
        }
    
        calledByParent(){
            console.log("i'm called")
        }
    
        render(){
            <div> hello </div>
        }
    }
    export default  connect(mapStateToProps, mapDispatchToProps)(B)
    

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题,但我不想让我的 API 依赖于 getWrappedInstance() 调用。事实上,类层次结构中的某些组件可能使用 connect() 并访问存储,而其他一些只是无状态组件,不需要额外的 Redux 层。

      我刚刚写了一个小(可能有点老套)的方法。请注意,它尚未经过全面测试,因此您可能需要进行一些调整才能使其在您自己的场景中正常工作。

      TypeScript(应该很容易转换为纯 JavaScript 语法):

      function exposeWrappedMethods(comp: React.ComponentClass<any>, proto?: any): any {
          if (!proto) {
              if (comp.prototype.constructor.name === 'Connect') {
                  // Only Redux component created with connect() is supported
                  proto = comp.prototype.constructor.WrappedComponent.prototype;
              } else {
                  console.warn('Trying to extend an invalid component.');
                  return comp;
              }
          }
      
          let prototypeName: string = proto.constructor.name;
          if (prototypeName.search(/^React.*Component.*/) < 0 && proto.__proto__) {
              for (let propertyName of Object.getOwnPropertyNames(proto)) {
                  if (!comp.prototype[propertyName]) {
                      let type: string = typeof proto[propertyName];
                      if (type === 'function') {
                          // It's a regular function
                          comp.prototype[propertyName] = function (...args: any[]) {
                              return this.wrappedInstance[propertyName](args);
                          };
                      } else if (type === 'undefined') {
                          // It's a property
                          Object.defineProperty(comp.prototype, propertyName, {
                              get: function () {
                                  return (this as any).wrappedInstance[propertyName];
                              },
                              set: function (value: any) {
                                  (this as any).wrappedInstance[propertyName] = value;
                              }
                          });
                      }
                  }
              }
      
              return exposeWrappedMethods(comp, proto.__proto__);
          }
      
          return comp;
      }

      只需用exposeWrappedMethods 包装您的connect() 调用即可使用它。它将添加您自己的类(和子类)中的所有方法和属性,但不会覆盖已经存在的方法(即来自 React.Component 基类的方法)。

      export default exposeWrappedMethods(
          connect<any, any, Properties>(
              (state: ApplicationState) => state.counter,
              CounterState.actionCreators,
              null,
              { pure: false, withRef: true } // It requires use of "withRef: true"
          )(Counter)) as typeof Counter;

      希望您(或其他人)觉得它有用。

      /卢卡斯

      【讨论】:

        猜你喜欢
        • 2021-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-29
        • 2011-12-01
        相关资源
        最近更新 更多