我在React中有一个用户注册表格,当用户名和密码文本字段的内容更改时,该表格会更新状态,例如:
<TextField onChange={e => this.updateUser(e)} />
updateUser(
evt: React.ChangeEvent<
HTMLTextAreaElement | HTMLInputElement | HTMLSelectElement
>
) {
const user = evt.target.value;
this.setState({ user });
}
但是,我想泛化updateUser()
和updatePassword()
函数,以便在向组件中添加更多字段时可以调用类似updateField(e, "password")
的名称。而不是编写新功能来更新状态中的每个字段。
我已经尝试过:
updateField(
evt: React.ChangeEvent<
HTMLTextAreaElement | HTMLInputElement | HTMLSelectElement
>,
field: string
) {
let updatedField = {};
updatedField[field] = evt.target.value; // error here
this.setState(updatedField);
}
我得到的错误是
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
No index signature with a parameter of type 'string' was found on type '{}'
我没有这样做
<TextField onChange={e => this.setState({user:e.target.value})} />
因为我的更新功能实际上比我在此处粘贴的功能要多
答案 0 :(得分:2)
您的尝试即将结束。您遇到的问题是string
的字段关键字太宽,它可能是任何东西,因此类型检查器将不允许它用作状态的关键字。您想要的是将密钥约束为您状态的密钥。假设您处于Component
是状态类型参数的MyState
中,这应该可以解决问题:
updateField<K extends keyof MyState>(
event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement | HTMLSelectElement>,
field: K
) {
const { value } = event.target;
this.setState({
[field]: value
} as Pick<MyProps, K>);
}
答案 1 :(得分:0)
收到此错误的原因是,当您声明以下内容时:
let updatedField = {};
变量updatedField
的类型为空对象。因此,当您尝试在其上设置属性时,TypeScript会告诉您您不能执行此操作,因为根据定义,空对象没有属性:在类型'上未找到参数类型为'string'的索引签名。 {}'
解决问题的一种简单方法是将您的代码更改为此:
updateField(
evt: React.ChangeEvent<
HTMLTextAreaElement | HTMLInputElement | HTMLSelectElement
>,
field: string
) {
this.setState({
[field]: evt.target.value
});
}
这将立即创建一个具有动态"computed" property名称(您的字段)和事件传递的值的对象,然后将其提供给setState
。
编辑:正如Aaron Beall所说,TypeScript在此处显示错误,因为计算出的属性不是您所在州类型的一部分。你应该参考他们的答案
答案 2 :(得分:0)
您可以使用高阶函数来概括更新特定字段。这是一个示例实现:
class ExampleForm extends React.Component {
state = {
name: '',
password: ''
}
setStateFromValue = prop => ({target:{value}}) => {
this.setState({[prop]: value})
}
render () {
return (
<form>
<input onChange={this.setStateFromValue('name')} />
<input type="password" onChange={this.setStateFromValue('password')} />
<div>
State: {JSON.stringify(this.state)}
</div>
</form>
)
}
}
ReactDOM.render(<ExampleForm />, document.querySelector("#form"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="form"></div>