Javascript 挂载后以编程方式关注表单元素
我有一个表单组件(FormComponent),当单击同级按钮组件时,我需要以编程方式关注它。我曾经能够调用Javascript 挂载后以编程方式关注表单元素,javascript,reactjs,Javascript,Reactjs,我有一个表单组件(FormComponent),当单击同级按钮组件时,我需要以编程方式关注它。我曾经能够调用this.refs.myForm.focus(),它(给定myForm作为FormComponent)被编写为在内部的第一个表单字段上调用.focus()。但是,我已经将一些行为重构并抽象为一个更高阶的组件来包装FormComponent,所以现在,FormComponent上的.focus()方法被包装器组件截取 使用React 0.14.x(因此我不需要ReactDOM.findDOM
this.refs.myForm.focus()
,它(给定myForm
作为FormComponent)被编写为在内部的第一个表单字段上调用.focus()
。但是,我已经将一些行为重构并抽象为一个更高阶的组件来包装FormComponent,所以现在,FormComponent上的.focus()
方法被包装器组件截取
使用React 0.14.x(因此我不需要ReactDOM.findDOMnode()
用于DOM组件):
//FormComponent
类FormComponentBase扩展了React.Component{
焦点(){
this.refs.firstField.focus();
}
render(){
返回(
);
}
}
//将FormComponent包装在具有抽象/可重用功能的包装器组件中
const FormComponent=hocWrapper(FormComponent);
//其他组件
类OtherComponent扩展React.Component{
把手舔(ev){
//错误这不起作用,因为hocWrapper组件正在拦截.focus()调用
this.refs.myForm.focus();
}
render(){
返回(
集中
);
}
}
传递一个
focus
prop并管理表单的第一个元素是否集中在OtherComponent
中的状态似乎很可笑。我知道您可以使用defineProperty
(或类似的东西)创建get
/set
属性,其中访问实例属性调用引擎盖下的方法来生成结果,但是JS是否有Ruby的missingMethod
或PHP的\uu调用
之类的东西,我可以在我的hocWrapper
上定义一个catch-all方法,它只将方法调用传递给包装好的组件?我以前在通过HOC包装器组件调用其他方法时遇到过这个问题,但我想我只是在HOC包装器上定义了一个同名的pass-thru方法(我很确定这是错误的方法)。使用ref回调函数可以相当容易地向上传递ref,而不是向下传递焦点状态
类FormComponentBase扩展了React.Component{
render(){
返回(
this.props.passNode(node)}/>
);
}
}
类OtherComponent扩展React.Component{
接收节点(节点){
如果(!this.state.node)this.setState({node})
}
render(){
返回(
this.state.node.focus()}>focus
);
}
}
更新:一种更为惯用的方式,它不会将节点传递给上强>
var FormComponentBase=React.createClass({
render(){
返回
node&&this.props.shouldFocus&&node.focus()
}/>
}
})
var OtherComponent=React.createClass({
getInitialState(){
返回{shouldFocus:false}
},
切换焦点(节点){
//切换以进行演示
this.setState({shouldFocus:!this.state.shouldFocus})
},
render:function(){
返回(
this.toggleFocus()}>focus
)
}
});
这里的自动对焦是否足够?否<代码>自动对焦
用于页面最初加载时。我需要在初始页面加载后的任何时候以编程方式关注一个字段。实际上,在上一次迭代中,我在同一个组件上使用了类似的东西,但它看起来像一个React反模式,因为所有内容都应该沿着呈现树向下流动。我的看法错了吗?我不认为这违背了反应的美德。许多组件以循环方式一起工作,传递回调函数并将参数发送回父级。最可靠的方法是从parent/redux传递焦点值,但是如果有很多元素,那么可能会变得非常冗长,因此可能不值得这样做。或者,执行类似于this.props.shouldFocus&&node.focus()}/>的操作。实际上,这似乎是一种非常简单的方法,您不必传递任何备份。对于您的shouldFocus
示例,这意味着我需要跟踪OtherComponent
中的状态,它将shoulldfocus
设置为true
,然后在字段模糊时将其设置为false
。对我来说,这听起来像是疯狂的恶性循环。在我的应用程序的某些地方,跟踪情态动词的打开状态已经很有趣了。这个按钮不会切换焦点。它只是在单击时设置焦点,就这样。因此,您最初的解决方案可以更好地解决问题。如果你把它还原,我会把它标记为答案。
// 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>
);
}
}
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>
);
}
}
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>
)
}
});