我的用例如下: products.js文件在底部包含一个表格和一个表单。在桌子上,我有一排产品,每个产品都有自己的“删除”和“更新”按钮。更新按钮呈现在productsRow.js文件中。当我单击任何产品上的“更新”按钮时,我希望该信息从productRow.js到树上传递到productsTable.js,products.js,然后到productForm.js,以便该信息以产品形式填充,因此我可以进行更新。我有一些逻辑可以做到这一点,并且表格已正确填充。问题是我不确定为什么当我尝试对下一个字段进行更改时,产品表单字段会恢复为旧值。示例我尝试更改产品名称(我可以),但是一旦我尝试更改类别字段,我的名称字段就会回到以前的产品名称。 我需要更新方面的帮助。下面是我的代码:
ProductForm.js
import React, { Component } from 'react';
const RESET_VALUES = {category: '', price: '', name: '', instock: false}
class ProductForm extends Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
this.handleUpdate = this.handleUpdate.bind(this)
this.handleSave = this.handleSave.bind(this)
this.state = {
product: Object.assign({}, RESET_VALUES),
updateRow: '',
enableUpdateBtn: true,
errors: {}
}
}
handleChange(e) {
const target = e.target
const value = target.value
const name = target.name
this.setState((prevState) => {
prevState.product[name] = value
return { product: prevState.product }
})
}
componentDidUpdate(prevProps, prevState) {
//console.log('[componentDidUpdate]', prevState);
//console.log('[componentDidUpdate2]', prevProps);
if (this.props.updateRow !== '') {
if (this.state.enableUpdateBtn === true){
this.setState({enableUpdateBtn: false});
}
this.name.value = this.props.updateRow.name;
this.category.value = this.props.updateRow.category;
this.price.value = this.props.updateRow.price;
if(this.props.updateRow.instock==="true") {
this.inStockTrue.value = "true" } else {
this.inStockTrue.value = 1;
}
//update prevState to new values
//if(prevState.updateRow != this.prevState)
}
//console.log('[componentDidUpdate After]', prevState);
//console.log('[componentDidUpdate After]', this.state.prevState);
}
handleUpdate = async () => {
console.log(this.state.product);
try {
const response = await fetch('http://localhost:5000/products/update/'+ this.state.product.id, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
product: {
category: this.state.product.category,
price: this.state.product.price,
name: this.state.product.name,
instock: this.state.product.instock
}
})
});
}catch (err) {
console.log(err);
}
}
handleSave = async event => {
event.preventDefault();
try {
const response = await fetch('http://localhost:5000/products/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
product: {
category: this.state.product.category,
price: this.state.product.price,
name: this.state.product.name,
instock: this.state.product.instock
}
})
});
const responseData = await response.json();
console.log(responseData);
fetch('http://localhost:5000/products/get')
.then((resp) => resp.json())
.then((data) => {
let newProductArray = [];
data.map(p => {
let {product,_id,} = p; //destructure object
product.id = _id;
newProductArray.push(product); //make array of product objects
return null;
})
this.props.loadTable();
this.setState({product: RESET_VALUES});
})
.catch((err) => {
console.log(err)
})
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
} catch (err) {
console.log(err);
}
}
render () {
return (
<form>
<h4>Add a new product</h4>
<p>
<label>Name <br />
<input type="text" className="form-control" name="name" onChange={this.handleChange} ref={(input)=>{this.name = input}} value={this.state.product.name} required/></label>
</p>
<p>
<label>Category <br />
<input type="text" className="form-control" name="category" onChange={this.handleChange} ref={(input)=>{this.category = input}} value={this.state.product.category} required/></label>
</p>
<p>
<label>Price <br />
<input type="text" className="form-control" name="price" onChange={this.handleChange} ref={(input)=>{this.price = input}} value={this.state.product.price} required/></label>
</p>
<p>Is product in Stock? </p>
<input type="radio" name="instock" onChange={this.handleChange} ref={(input)=>{this.inStockTrue = input}} value="true" />True<br/>
<input type="radio" name="instock" onChange={this.handleChange} ref={(input)=>{this.inStockFalse = input}} value="false" />False
<br/>
<button type="button" className="btn btn-info" onClick={this.handleUpdate} disabled={this.state.enableUpdateBtn}>Update</button>
<input type="submit" className="btn btn-info ml-3" value="Save" onClick={this.handleSave}></input>
</form>
)
}
}
export default ProductForm
Products.js
import React, { Component } from 'react'
import Filters from './Filters'
import ProductTable from './ProductTable'
import ProductForm from './ProductForm'
// let PRODUCTS = {
// '1': {id: 1, category: 'Music', price: '$459.99', name: 'Clarinet', instock: true},
// '2': {id: 2, category: 'Music', price: '$5,000', name: 'Cello', instock: true},
// '3': {id: 3, category: 'Music', price: '$3,500', name: 'Tuba', instock: true},
// '4': {id: 4, category: 'Furniture', price: '$799', name: 'Chaise Lounge', instock: true},
// '5': {id: 5, category: 'Furniture', price: '$1,300', name: 'Dining Table', instock: true},
// '6': {id: 6, category: 'Furniture', price: '$100', name: 'Bean Bag', instock: true}
// };
class Products extends Component {
constructor(props) {
super(props)
this.state = {
filterText: '',
products: '',
productToBeUpdated: ''
}
this.handleFilter = this.handleFilter.bind(this)
this.handleDestroy = this.handleDestroy.bind(this)
//this.handleUpdate = this.handleUpdate.bind(this)
this.loadData = this.loadData.bind(this)
}
updateGrandparent(value){
this.setState({productToBeUpdated: value});
}
handleDestroy = async (productId) => {
try {
const response = await fetch('http://localhost:5000/products/delete/' + productId, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: productId
})
});
const responseData = await response.json();
console.log(responseData);
//Remove row from table
const index = this.state.products.findIndex(product => {
return product.id === productId;
});
console.log(index);
let copyProducts = [...this.state.products];
copyProducts.splice(index,1);
this.setState({products:copyProducts});
} catch (err) {
console.log(err);
}
}
componentDidMount() {
this.loadData();
}
loadData () {
fetch('http://localhost:5000/products/get')
.then((resp) => resp.json())
.then((data) => {
let newProductArray = [];
data.map(p => {
let {product,_id,} = p; //destructure object
product.id = _id;
newProductArray.push(product); //make array of product objects
this.setState({products: newProductArray});
return null;
})
})
.catch((err) => {
console.log(err)
})
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
}
handleFilter(filterInput) {
this.setState(filterInput)
}
handleSave = async event => {
//console.log( this.state.product.category, this.state.product.instock);
event.preventDefault();
try {
const response = await fetch('http://localhost:5000/products/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
product: {
category: this.state.product.category,
price: this.state.product.price,
name: this.state.product.name,
instock: this.state.product.instock
}
})
});
const responseData = await response.json();
console.log(responseData);
fetch('http://localhost:5000/products/get')
.then((resp) => resp.json())
.then((data) => {
let newProductArray = [];
data.map(p => {
let {product,_id,} = p; //destructure object
product.id = _id;
newProductArray.push(product); //make array of product objects
return null;
})
this.props.updateTable();
})
.catch((err) => {
console.log(err)
})
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
} catch (err) {
console.log(err);
}
}
render () {
return (
<div>
<h1>My Inventory</h1>
<Filters
onFilter={this.handleFilter}></Filters>
<ProductTable
products={this.state.products}
filterText={this.state.filterText}
onDestroy ={this.handleDestroy}
updateGrandparent={this.updateGrandparent.bind(this)}
>
</ProductTable>
<ProductForm
loadTable={this.loadData}
updateRow={this.state.productToBeUpdated}
></ProductForm>
</div>
)
}
}
export default Products
productRow.js
import React, { Component } from 'react'
class ProductRow extends Component {
destroy = (productId) => {
this.props.onDestroy(this.props.product.id);
}
handleClick() {
this.props.updateParent(this.props.product);
}
render () {
return (
<tr>
<td>{this.props.product.name}</td>
<td>{this.props.product.category}</td>
<td>{this.props.product.price}</td>
<td>{this.props.product.instock}</td>
<td ><button onClick={this.handleClick.bind(this)} className="btn btn-info">Update</button></td>
<td><button onClick={() => this.destroy(this.props.product.id)} className="btn btn-info">Delete</button></td>
</tr>
)
}
}
export default ProductRow