React Component 收到不正确的 prop 值
React Component receiving incorrect prop value
我有一个模态组件和一个表单组件。 Modal 是一个功能组件,而 Form 是一个 class 组件,因为这是我处理表单提交的地方。
Modal [父级] 将其所有道具传递给 Form。 Modal 的 props 对象中有三个值,两个字符串和一个数字。
字符串值符合预期,但数字(用作 ID)为 1,而不是预期的 10(在本例中)。这是一个问题,因为我试图将该值保存到状态中,但没有得到我期望的值。
特别的是,如果我 console.log(this.props)
在 render()
里面, props 对象被打印两次 ;第一次数字值为 1,第二次为 10。这发生在组件的初始渲染时,状态没有发生任何变化。
为什么会发生这种情况,如何获得我期望的实际值?
这是模态组件。
import React from 'react';
import Form from './Form';
const Modal = (props) => (
<div className="modal fade" id="createWorkitem" tabIndex="-1" role="dialog" aria-labelledby="createWorkitemLabel" aria-hidden="true">
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="createWorkitemLabel">
{/* 10 */}
Item #{ props.issueNumber }
</h5>
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
{/* Form needs props to POST */}
<Form
{...props}
/>
</div>
</div>
</div>
</div>
);
export default Modal;
这是表单组件
import React, { Component } from 'react';
import axios from 'axios';
import config from '../../../../../config';
const { create_issue_url } = config.init();
class Form extends Component {
constructor(props) {
super(props);
this.state = {
issueNumber: '',
title: '',
price: '',
duration: '',
description: ''
}
this.handleChange = this.handleChange.bind(this);
this.submitForm = this.submitForm.bind(this);
this.resetForm = this.resetForm.bind(this);
}
componentWillMount() {
// this prints once with wrong value
console.log(this.props);
}
componentDidMount() {
// this prints once with wrong value
console.log(this.props);
// this prints once with right value inside props object
console.log(this);
}
handleChange(e) {
this.setState({[e.target.id]: e.target.value});
}
submitForm(e) {
e.preventDefault();
let endpoint = `${create_issue_url}/${this.props.repo}`;
let msg = 'Are you sure you want to create this item?';
// Make sure
if(confirm(msg)) {
axios.post(endpoint, this.state)
.then(response => {
console.log(response.data.workitem);
// Clear form
this.resetForm();
// Show success alert
document.getElementById('successAlert').style.display = '';
// Hide it after 3 seconds
setTimeout(function hideAlert(){
document.getElementById('successAlert').style.display = 'none';
}, 3000);
})
.catch(err => {
console.log(err);
});
}
}
resetForm() {
this.setState({
title: '',
price: '',
duration: '',
description: ''
});
}
render() {
let { title, price, duration, description } = this.state;
// this prints twice
{console.log(this.props.issueNumber)}
return (
<form onSubmit={this.submitForm}>
<div id="successAlert" className="alert alert-success" role="alert"
style={{display: 'none'}}
>
Item created.
</div>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="title">Title</label>
<input onChange={this.handleChange} type="text" value={title} className="form-control" id="title" required/>
</div>
<div className="form-group col-md-3">
<label htmlFor="price">Price</label>
<input onChange={this.handleChange} type="number" value={price} className="form-control" id="price" required/>
</div>
<div className="form-group col-md-3">
<label htmlFor="duration">Duration</label>
<input onChange={this.handleChange} type="number" value={duration} className="form-control" id="duration"
placeholder="days" required
/>
</div>
</div>
<div className="form-group">
<label htmlFor="description">Description</label>
<textarea
onChange={this.handleChange}
className="form-control"
id="description"
style={{overflow: 'auto', resize: 'none'}}
value={description}
required
></textarea>
</div>
{/* Using modal footer as form footer because it works */}
<div className="modal-footer">
<button type="submit" className="btn btn-primary">Submit</button>
<button type="button" className="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</form>
);
}
}
export default Form;
行为是正确的。在加载时,您的模态组件接收的道具为 1。后来它更改为 10。因此,一旦值更改为 10,您的组件就会更新。componentDidMount 将在初始安装期间仅被调用一次。但是只要组件更新即收到更新的道具(在您的情况下为 issuenumber 10),就会调用 componentDidUpdate 和 render。
所以 render 最初会被调用两次,1 作为 prop 值,然后是 10。但是 componentDidMount 只会被调用一次(当 prop 值为 1 时)
现在问题是在 componentDidMount 中打印 console.log(this) vs console.log(this.props)。第一个案例显示 issuenumber 属性为 10,第二个案例显示为 1。我怀疑这是因为 chrome 开发人员工具正在使用实时更新优化打印。当你打印时 this
显然 prop 是 1,但是我觉得控制台正在实时更新打印(很快那个对象就会用新的 props 更新)
Console.log showing only the updated version of the object printed
按照此处的建议代替 console.log(this)
尝试
console.log(JSON.parse(JSON.stringify(this)));
这应该打印 1
希望这能解决问题。
我有一个模态组件和一个表单组件。 Modal 是一个功能组件,而 Form 是一个 class 组件,因为这是我处理表单提交的地方。
Modal [父级] 将其所有道具传递给 Form。 Modal 的 props 对象中有三个值,两个字符串和一个数字。
字符串值符合预期,但数字(用作 ID)为 1,而不是预期的 10(在本例中)。这是一个问题,因为我试图将该值保存到状态中,但没有得到我期望的值。
特别的是,如果我 console.log(this.props)
在 render()
里面, props 对象被打印两次 ;第一次数字值为 1,第二次为 10。这发生在组件的初始渲染时,状态没有发生任何变化。
为什么会发生这种情况,如何获得我期望的实际值?
这是模态组件。
import React from 'react';
import Form from './Form';
const Modal = (props) => (
<div className="modal fade" id="createWorkitem" tabIndex="-1" role="dialog" aria-labelledby="createWorkitemLabel" aria-hidden="true">
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="createWorkitemLabel">
{/* 10 */}
Item #{ props.issueNumber }
</h5>
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
{/* Form needs props to POST */}
<Form
{...props}
/>
</div>
</div>
</div>
</div>
);
export default Modal;
这是表单组件
import React, { Component } from 'react';
import axios from 'axios';
import config from '../../../../../config';
const { create_issue_url } = config.init();
class Form extends Component {
constructor(props) {
super(props);
this.state = {
issueNumber: '',
title: '',
price: '',
duration: '',
description: ''
}
this.handleChange = this.handleChange.bind(this);
this.submitForm = this.submitForm.bind(this);
this.resetForm = this.resetForm.bind(this);
}
componentWillMount() {
// this prints once with wrong value
console.log(this.props);
}
componentDidMount() {
// this prints once with wrong value
console.log(this.props);
// this prints once with right value inside props object
console.log(this);
}
handleChange(e) {
this.setState({[e.target.id]: e.target.value});
}
submitForm(e) {
e.preventDefault();
let endpoint = `${create_issue_url}/${this.props.repo}`;
let msg = 'Are you sure you want to create this item?';
// Make sure
if(confirm(msg)) {
axios.post(endpoint, this.state)
.then(response => {
console.log(response.data.workitem);
// Clear form
this.resetForm();
// Show success alert
document.getElementById('successAlert').style.display = '';
// Hide it after 3 seconds
setTimeout(function hideAlert(){
document.getElementById('successAlert').style.display = 'none';
}, 3000);
})
.catch(err => {
console.log(err);
});
}
}
resetForm() {
this.setState({
title: '',
price: '',
duration: '',
description: ''
});
}
render() {
let { title, price, duration, description } = this.state;
// this prints twice
{console.log(this.props.issueNumber)}
return (
<form onSubmit={this.submitForm}>
<div id="successAlert" className="alert alert-success" role="alert"
style={{display: 'none'}}
>
Item created.
</div>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="title">Title</label>
<input onChange={this.handleChange} type="text" value={title} className="form-control" id="title" required/>
</div>
<div className="form-group col-md-3">
<label htmlFor="price">Price</label>
<input onChange={this.handleChange} type="number" value={price} className="form-control" id="price" required/>
</div>
<div className="form-group col-md-3">
<label htmlFor="duration">Duration</label>
<input onChange={this.handleChange} type="number" value={duration} className="form-control" id="duration"
placeholder="days" required
/>
</div>
</div>
<div className="form-group">
<label htmlFor="description">Description</label>
<textarea
onChange={this.handleChange}
className="form-control"
id="description"
style={{overflow: 'auto', resize: 'none'}}
value={description}
required
></textarea>
</div>
{/* Using modal footer as form footer because it works */}
<div className="modal-footer">
<button type="submit" className="btn btn-primary">Submit</button>
<button type="button" className="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</form>
);
}
}
export default Form;
行为是正确的。在加载时,您的模态组件接收的道具为 1。后来它更改为 10。因此,一旦值更改为 10,您的组件就会更新。componentDidMount 将在初始安装期间仅被调用一次。但是只要组件更新即收到更新的道具(在您的情况下为 issuenumber 10),就会调用 componentDidUpdate 和 render。
所以 render 最初会被调用两次,1 作为 prop 值,然后是 10。但是 componentDidMount 只会被调用一次(当 prop 值为 1 时)
现在问题是在 componentDidMount 中打印 console.log(this) vs console.log(this.props)。第一个案例显示 issuenumber 属性为 10,第二个案例显示为 1。我怀疑这是因为 chrome 开发人员工具正在使用实时更新优化打印。当你打印时 this
显然 prop 是 1,但是我觉得控制台正在实时更新打印(很快那个对象就会用新的 props 更新)
Console.log showing only the updated version of the object printed
按照此处的建议代替 console.log(this)
尝试
console.log(JSON.parse(JSON.stringify(this)));
这应该打印 1
希望这能解决问题。