安装后以编程方式关注表单元素

时间:2016-04-19 03:11:32

标签: javascript reactjs

我有一个表单组件(FormComponent),我需要在单击一个兄弟按钮组件时以编程方式关注它。我曾经能够调用this.refs.myForm.focus()(其中myForm为FormComponent)被写入内部第一个表单字段上的.focus()。但是,我已经将一些行为重构并抽象为包含FormComponent的高阶组件,所以现在,FormComponent上的.focus()方法被包装器组件截获。

使用React 0.14.x(因此DOM组件不需要ReactDOM.findDOMnode()):

// FormComponent
class FormComponentBase extends React.Component {
    focus() {
        this.refs.firstField.focus();
    }

    render() {
        return (
            <form ...>
                <input ref="firstField" />
            </form>
        );
     }
}

// Wraps FormComponent in a wrapper component with abstracted/reusable functionality
const FormComponent = hocWrapper(FormComponent);

// OtherComponent
class OtherComponent extends React.Component {
    handleClick(ev) {
        // ERROR This doesn't work because the hocWrapper component is intercepting the .focus() call
        this.refs.myForm.focus();
    }

    render() {
        return (
            <div>
                <button onClick={this.handleClick.bind(this)}>Focus</button>
                <FormComponent ref="myForm" />
            </div>
        );
     }
}

传递focus道具并管理表单的第一个元素是否集中在OtherComponent的状态似乎很荒谬。我知道你可以使用get(或类似的东西)创建set / defineProperty属性,其中访问实例属性调用引擎下的方法来生成结果,但是JS有一些东西比如Ruby的missingMethod或PHP的__call,我可以在我的hocWrapper上定义一个只能将方法调用传递给包装组件的catch-all方法?我在通过HOC包装器组件调用其他方法之前遇到过这个问题,但我想我只是在HOC包装器上定义了一个同名的pass-thru方法(我相当肯定这是错误的方法)。

1 个答案:

答案 0 :(得分:1)

不是将焦点状态向下传递,而是可以使用ref回调函数轻松地传递ref。 Here's a fiddle illustrating

class FormComponentBase extends React.Component {
  render() {
    return (
      <form ...>
         <input ref={node => this.props.passNode(node)} />
      </form>
    );
  }
}

class OtherComponent extends React.Component {
  receiveNode(node) {
    if (!this.state.node) this.setState({ node })
  }

  render() {
    return (
      <div>
        <button onClick={() => this.state.node.focus()}>Focus</button>
        <FormComponent passNode={this.receiveNode} />
      </div>
    );
  }
}    

更新:一种不通过节点的惯用方法。 updated fiddle

var FormComponentBase = React.createClass({
  render() {
    return <input ref={ node => 
      node && this.props.shouldFocus && node.focus()
    }/>
  }
})

var OtherComponent = React.createClass({
  getInitialState() {
    return { shouldFocus: false }
  },

  toggleFocus(node) {
    // toggle for demonstration
    this.setState({ shouldFocus: !this.state.shouldFocus })
  },

  render: function() {
    return (
      <div>
        <button onClick={() => this.toggleFocus() }>focus</button>
        <Child shouldFocus={this.state.shouldFocus} />
      </div>
    )
  }
});