与 props 同步状态以实现 reactjs 中表单输入的两种方式绑定
sync state with props to achive two way binding for form input in reactjs
我有一个很长的表单(准确地说是 75 个输入),因为我正在使用 redux 来管理我的应用程序状态,所以每当我想编辑这个表单时,我想将表单的 setState 设置为 prop 以允许编辑.
示例代码:
class VisitCard extends Component {
constructor(props) {
super(props); //props.visit = {name:'randome name', data:'etc..'}
this.state = Object.assign({},props.visit);
this.bindInput = this.bindInput.bind(this);
}
//BindInput will return props for Inputs, to achive two way binding
bindInput(config){
const {name,...props} = config;
return {
value : this.state[name],
onChange: event => this.setState({[name]:event.target.value}),
...props
}
}
render(){
return <div>
<input {...this.bindInput({name:'name', type:'text'})} />
<input {...this.bindInput({name:'data', type:'text'})} />
</div>
}
}
上面的代码工作完美,问题是当这个组件安装时,它给我错误 "Cannot update during an existing state transition"
有时如果道具中没有预定义值,输入的值将是未定义的,所以在道具从服务器加载并更新组件后我得到另一个错误 "trying to change input from uncontrolled to controled" 那是因为 this.state[name]
未定义然后我得到一个值
所以我做错了什么?我如何 link 具有道具值的组件的状态,并确保如果道具改变,状态也会改变,同时,如果状态改变,这不会影响道具。
我希望修改您的代码以符合以下逻辑将解决您的问题。在代码中寻找注释以进行解释
class VisitCard extends Component {
constructor(props) {
super(props);
//set your state to have a key that holds your prop value.
this.state = { visit: props.visit };
this.bindInput = this.bindInput.bind(this);
}
componentWillReceiveProps(nextProps) {
//if your props is received after the component is mounted, then this function will update the state accordingly.
if(this.props.visit !== nextProps.visit) {
this.setState({visit: nextProps.visit});
}
}
bindInput(config){
const {name,...props} = config;
// return defaultValue which you get from the props.
// you can add `value: this.state.visit[name]` to the below object only if you want your input to be controlled, else it can be ignored.
return {
defaultValue : this.props.visit[name],
onChange: event => this.setState(
{visit: { ...this.state.visit,
[name]:event.target.value}
}),
...props
}
}
render(){
// render empty if your props has not yet arrived.
if(!this.props.visit) {
return (<div />);
}
// render after you have values in props
return (<div>
<input {...this.bindInput({name:'name', type:'text'})} />
<input {...this.bindInput({name:'data', type:'text'})} />
</div>);
}
}
我有一个很长的表单(准确地说是 75 个输入),因为我正在使用 redux 来管理我的应用程序状态,所以每当我想编辑这个表单时,我想将表单的 setState 设置为 prop 以允许编辑.
示例代码:
class VisitCard extends Component {
constructor(props) {
super(props); //props.visit = {name:'randome name', data:'etc..'}
this.state = Object.assign({},props.visit);
this.bindInput = this.bindInput.bind(this);
}
//BindInput will return props for Inputs, to achive two way binding
bindInput(config){
const {name,...props} = config;
return {
value : this.state[name],
onChange: event => this.setState({[name]:event.target.value}),
...props
}
}
render(){
return <div>
<input {...this.bindInput({name:'name', type:'text'})} />
<input {...this.bindInput({name:'data', type:'text'})} />
</div>
}
}
上面的代码工作完美,问题是当这个组件安装时,它给我错误 "Cannot update during an existing state transition"
有时如果道具中没有预定义值,输入的值将是未定义的,所以在道具从服务器加载并更新组件后我得到另一个错误 "trying to change input from uncontrolled to controled" 那是因为 this.state[name]
未定义然后我得到一个值
所以我做错了什么?我如何 link 具有道具值的组件的状态,并确保如果道具改变,状态也会改变,同时,如果状态改变,这不会影响道具。
我希望修改您的代码以符合以下逻辑将解决您的问题。在代码中寻找注释以进行解释
class VisitCard extends Component {
constructor(props) {
super(props);
//set your state to have a key that holds your prop value.
this.state = { visit: props.visit };
this.bindInput = this.bindInput.bind(this);
}
componentWillReceiveProps(nextProps) {
//if your props is received after the component is mounted, then this function will update the state accordingly.
if(this.props.visit !== nextProps.visit) {
this.setState({visit: nextProps.visit});
}
}
bindInput(config){
const {name,...props} = config;
// return defaultValue which you get from the props.
// you can add `value: this.state.visit[name]` to the below object only if you want your input to be controlled, else it can be ignored.
return {
defaultValue : this.props.visit[name],
onChange: event => this.setState(
{visit: { ...this.state.visit,
[name]:event.target.value}
}),
...props
}
}
render(){
// render empty if your props has not yet arrived.
if(!this.props.visit) {
return (<div />);
}
// render after you have values in props
return (<div>
<input {...this.bindInput({name:'name', type:'text'})} />
<input {...this.bindInput({name:'data', type:'text'})} />
</div>);
}
}