我有一个表单组件(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方法(我相当肯定这是错误的方法)。
答案 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>
)
}
});