React受控TextField输入字符后失焦,如何修复该问题?
解决受控TextField输入时失去焦点的问题
这个问题的根源在于你在Config和MenuEntry组件的render方法里直接修改了组件实例的属性(this.owner = owner、this.value = value),这违反了React中render方法应该是纯函数的原则。
为什么会导致焦点丢失?
每次你在输入框输入字符时,会触发setUrl方法修改父组件的state,父组件随之重新render。这时候子组件Config的render方法会再次执行,你在这里给this.owner重新赋值的操作,会让React误以为当前的Config组件是一个全新的实例,于是会卸载旧的组件再重新挂载新的——旧的输入框被销毁,新的输入框自然就失去焦点了。
修复方案
我们需要移除render中对组件实例属性的赋值,直接通过this.props访问父组件传递过来的值。
修改后的Config组件:
"use strict" import React from "react"; import createReactClass from "create-react-class"; import RaisedButton from 'material-ui/RaisedButton'; import TextField from 'material-ui/TextField'; import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card'; export var Config = createReactClass({ setConfig: function() { localStorage.serverUrl = this.props.owner.state.serverUrl; location.reload(); }, setUrl: function(evt) { // 直接通过props访问父组件,不再依赖this.owner this.props.owner.setState({serverUrl: evt.target.value}); }, render: function() { const { owner } = this.props; // 移除this.owner = owner的赋值操作 return ( <div> <CardTitle title={__("Server")} /> <CardText> <TextField id="serverUrl" floatingLabelText={__("Server URL")} value={owner.state.serverUrl} onChange={this.setUrl} /> </CardText> <CardActions> <RaisedButton label={__("Apply")} onTouchTap={this.setConfig} /> </CardActions> </div> ); } });
修改后的MenuEntry组件:
"use strict"; import React from "react"; import createReactClass from "create-react-class"; import MenuItem from 'material-ui/MenuItem'; export var MenuEntry = createReactClass({ onChange: function() { const { owner, value } = this.props; // 直接从props获取所需值,不再依赖this.owner和this.value owner.setState({ menuOpen: false, systemMenuOpen: false, location: value }); }, render: function() { const { title, owner, value, color } = this.props; // 移除this.owner和this.value的赋值操作 const selected = owner.state.location === value; return ( <MenuItem checked={selected} onTouchTap={this.onChange} backgroundColor={color} > {title} </MenuItem> ); } });
额外优化建议(可选)
为了让组件耦合度更低,更符合React的单向数据流原则,建议不要让子组件直接修改父组件的state,而是由父组件传递回调函数给子组件。比如:
- 在父组件中定义处理URL变化的方法:
handleServerUrlChange = (url) => { this.setState({ serverUrl: url }); }
- 把这个方法传递给
Config组件:
<Config owner={this} onServerUrlChange={this.handleServerUrlChange} />
- 在
Config组件中调用这个回调:
setUrl: function(evt) { this.props.onServerUrlChange(evt.target.value); }
这样修改后,输入框在输入时就不会再丢失焦点了。
内容的提问来源于stack exchange,提问作者Ruediger Jungbeck
相关产品推荐
相关产品推荐

