在 React 中提交表单后刷新页面
Refresh page after submit form in React
当我在输入中更改我的程序的价格并单击更新按钮时,一切都很好,价格发生了变化,但是当我刷新我的页面时,我出现了一个错误,即使我没有修改价格和我刚刷新页面就出现这个错误,我不明白为什么
这是错误的截图,你会在下面找到我的代码
应用程序
import React, { useState, useEffect } from 'react';
import './css/App.css';
import './css/Products.css';
import axios from 'axios';
import Navigation from './Components/Navigation';
import Products from './Components/Products';
import {BrowserRouter as Router, Route, Switch,} from 'react-router-dom';
import ProductsDetails from './Components/ProductsDetails';
export default function App() {
const [productsData, setProductsData] = useState([]);
useEffect(() => {
axios.get("https://fakestoreapi.com/products?limit=7").then((res) => {
setProductsData(res.data);
});
}, []);
const updatePrice = (id, price) => {
setProductsData((productsData) =>
productsData.map((product) =>
product.id === Number(id)
? {
...product,
price: Number(price)
}
: product
)
);
};
return (
<div className="App">
<Router>
<Navigation/>
<Switch>
<Route
path="/products-details/:id"
render={(props) => (
<ProductsDetails
products={productsData}
updatePrice={updatePrice}
{...props}
/>
)}
/>
<Route path="/">
<Products products={productsData}
/>
</Route>
</Switch>
</Router>
</div>
);
}
产品
import React, { Component } from 'react';
import '../css/Products.css';
import './ProductsDetails'
import {Link} from 'react-router-dom'
export default class Products extends Component {
render() {
const listsProducts = this.props.products.map((listProduct) => {
return (
<tbody className="products__body" key={listProduct.id}>
<tr>
<td><Link to={{pathname: "/products-details/" + listProduct.id}}>{listProduct.title}</Link></td>
<td><p className={`${listProduct.category==="men's clothing" ? "category__orange" : "category__green"}`}>{listProduct.category}</p></td>
<td>{Number(listProduct.price).toFixed(2)}</td>
<td>
{Number(listProduct.price * 1.2).toFixed(2)} €
</td>
</tr>
</tbody>
);
});
return (
<main className="products">
<h1 className="products__title">Products management</h1>
<table cellSpacing="0">
<thead className="products__head">
<tr>
<th className="table--title">Product name</th>
<th className="table--title">Category</th>
<th className="table--title">Price</th>
<th className="table--title">Price (including VAT)</th>
</tr>
</thead>
{listsProducts}
</table>
</main>
);
}
}
产品详情
import React, { Component } from 'react'
import '../css/ProductsDetails.css'
import {AiOutlineArrowLeft} from "react-icons/ai";
import {Link} from 'react-router-dom'
export default class ProductsDetails extends Component {
constructor(props) {
super(props);
// ajout de deux états l'id qu'on récupére de l'API et le prix qui vaut 0
this.state = {
id: this.props.match.params.id,
price: 0
};
}
// mise en place d'une méthode qui permet de modifier la valeur dans l'input texte
updatePrice = (e) => {
console.log(e);
this.setState({
price: e.target.value
});
};
/*
mise en place d'une méthode qui permet au clique du bouton de changer le prix
grâce à la méthode "updatePrice ainsi que l'id et l'état du prix du produit
*/
submitHandler = (e) => {
// permet au clique du bouton que concerver localement la valeur modifiée
localStorage.setItem('price', this.state.price)
e.preventDefault();
const {
match: {
params: { id }
}
} = this.props;
this.props.updatePrice(id, this.state.price);
};
// permet de garder la valeur modifiée au refresh de la page
componentDidMount() {
const price = localStorage.getItem('price')
this.setState({price});
}
render() {
const {
match: {
params: { id }
},
products
} = this.props;
// Ajout d'une variable qui récupére le premier id trouvé dans le tableau "products"
const listProduct = products.find((product) => product.id === Number(id));
return (
<div className="products__details">
<Link to="/">
<AiOutlineArrowLeft className="nav__arrow" />
</Link>
<h1 className="details__title">{listProduct.title}</h1>
<div className="details__align--desk">
<div className="details__img">
<img
className="product__img"
src={listProduct.image}
alt="Affichage du produit"
/>
</div>
<div className="products__align--desk">
<h2 className="product__title">Description</h2>
<p className="product__description">{listProduct.description}</p>
<h2 className="product__title">Price</h2>
<form className="form__price" onSubmit={this.submitHandler}>
<input
name="price"
className="input__price"
type="text"
defaultValue={Number(listProduct.price).toFixed(2)}
onChange={this.updatePrice}
/>
<p>
Price (including VAT):{" "}
{Number(listProduct.price * 1.2).toFixed(2)} €
</p>
<br />
<input
className="btn__update"
type="submit"
value="Update product"
/>
</form>
</div>
<div className="category__align--desk">
<h2 className="product__title">Category</h2>
<p className={`${listProduct.category==="men's clothing" ? "category__orange" : "category__green"} product__category`}>{listProduct.category}</p>
</div>
</div>
</div>
);
}
}
预先感谢您的解释
我怀疑是因为当 listProduct
是 null
时您没有覆盖状态。当它加载时,它会立即呈现,因为它正在获取您的产品数据,因此 products
可以为空,而 .find()
将 return 一个 null
,然后您正在尝试在 null
时渲染 listProduct.title
。理想情况下,您的渲染应该检查 listProduct
是否可用。
更好的是,让你的组件有一些状态,比如加载数据、显示数据、没有数据。
<Card>
{ dataStatus === "Loaded" &&
<Card.Title>{person.Name}</Card.Title>
}
{ dataStatus === "Loading" &&
<Card.Loader>Loading...</Card.Loader>
}
{ dataStatus === "Error" &&
<Card.Error>Sorry, we had an oopsie...</Card.Error>
}
{ dataStatus === "Empty" &&
<Card.Empty>Looks like we're missing something...</Card.Empty>
}
</Card>
这里有进一步的解释和代码示例:https://davidlozzi.com/2021/05/14/keeping-react-components-state-top-of-mind/
当我在输入中更改我的程序的价格并单击更新按钮时,一切都很好,价格发生了变化,但是当我刷新我的页面时,我出现了一个错误,即使我没有修改价格和我刚刷新页面就出现这个错误,我不明白为什么
这是错误的截图,你会在下面找到我的代码
应用程序
import React, { useState, useEffect } from 'react';
import './css/App.css';
import './css/Products.css';
import axios from 'axios';
import Navigation from './Components/Navigation';
import Products from './Components/Products';
import {BrowserRouter as Router, Route, Switch,} from 'react-router-dom';
import ProductsDetails from './Components/ProductsDetails';
export default function App() {
const [productsData, setProductsData] = useState([]);
useEffect(() => {
axios.get("https://fakestoreapi.com/products?limit=7").then((res) => {
setProductsData(res.data);
});
}, []);
const updatePrice = (id, price) => {
setProductsData((productsData) =>
productsData.map((product) =>
product.id === Number(id)
? {
...product,
price: Number(price)
}
: product
)
);
};
return (
<div className="App">
<Router>
<Navigation/>
<Switch>
<Route
path="/products-details/:id"
render={(props) => (
<ProductsDetails
products={productsData}
updatePrice={updatePrice}
{...props}
/>
)}
/>
<Route path="/">
<Products products={productsData}
/>
</Route>
</Switch>
</Router>
</div>
);
}
产品
import React, { Component } from 'react';
import '../css/Products.css';
import './ProductsDetails'
import {Link} from 'react-router-dom'
export default class Products extends Component {
render() {
const listsProducts = this.props.products.map((listProduct) => {
return (
<tbody className="products__body" key={listProduct.id}>
<tr>
<td><Link to={{pathname: "/products-details/" + listProduct.id}}>{listProduct.title}</Link></td>
<td><p className={`${listProduct.category==="men's clothing" ? "category__orange" : "category__green"}`}>{listProduct.category}</p></td>
<td>{Number(listProduct.price).toFixed(2)}</td>
<td>
{Number(listProduct.price * 1.2).toFixed(2)} €
</td>
</tr>
</tbody>
);
});
return (
<main className="products">
<h1 className="products__title">Products management</h1>
<table cellSpacing="0">
<thead className="products__head">
<tr>
<th className="table--title">Product name</th>
<th className="table--title">Category</th>
<th className="table--title">Price</th>
<th className="table--title">Price (including VAT)</th>
</tr>
</thead>
{listsProducts}
</table>
</main>
);
}
}
产品详情
import React, { Component } from 'react'
import '../css/ProductsDetails.css'
import {AiOutlineArrowLeft} from "react-icons/ai";
import {Link} from 'react-router-dom'
export default class ProductsDetails extends Component {
constructor(props) {
super(props);
// ajout de deux états l'id qu'on récupére de l'API et le prix qui vaut 0
this.state = {
id: this.props.match.params.id,
price: 0
};
}
// mise en place d'une méthode qui permet de modifier la valeur dans l'input texte
updatePrice = (e) => {
console.log(e);
this.setState({
price: e.target.value
});
};
/*
mise en place d'une méthode qui permet au clique du bouton de changer le prix
grâce à la méthode "updatePrice ainsi que l'id et l'état du prix du produit
*/
submitHandler = (e) => {
// permet au clique du bouton que concerver localement la valeur modifiée
localStorage.setItem('price', this.state.price)
e.preventDefault();
const {
match: {
params: { id }
}
} = this.props;
this.props.updatePrice(id, this.state.price);
};
// permet de garder la valeur modifiée au refresh de la page
componentDidMount() {
const price = localStorage.getItem('price')
this.setState({price});
}
render() {
const {
match: {
params: { id }
},
products
} = this.props;
// Ajout d'une variable qui récupére le premier id trouvé dans le tableau "products"
const listProduct = products.find((product) => product.id === Number(id));
return (
<div className="products__details">
<Link to="/">
<AiOutlineArrowLeft className="nav__arrow" />
</Link>
<h1 className="details__title">{listProduct.title}</h1>
<div className="details__align--desk">
<div className="details__img">
<img
className="product__img"
src={listProduct.image}
alt="Affichage du produit"
/>
</div>
<div className="products__align--desk">
<h2 className="product__title">Description</h2>
<p className="product__description">{listProduct.description}</p>
<h2 className="product__title">Price</h2>
<form className="form__price" onSubmit={this.submitHandler}>
<input
name="price"
className="input__price"
type="text"
defaultValue={Number(listProduct.price).toFixed(2)}
onChange={this.updatePrice}
/>
<p>
Price (including VAT):{" "}
{Number(listProduct.price * 1.2).toFixed(2)} €
</p>
<br />
<input
className="btn__update"
type="submit"
value="Update product"
/>
</form>
</div>
<div className="category__align--desk">
<h2 className="product__title">Category</h2>
<p className={`${listProduct.category==="men's clothing" ? "category__orange" : "category__green"} product__category`}>{listProduct.category}</p>
</div>
</div>
</div>
);
}
}
预先感谢您的解释
我怀疑是因为当 listProduct
是 null
时您没有覆盖状态。当它加载时,它会立即呈现,因为它正在获取您的产品数据,因此 products
可以为空,而 .find()
将 return 一个 null
,然后您正在尝试在 null
时渲染 listProduct.title
。理想情况下,您的渲染应该检查 listProduct
是否可用。
更好的是,让你的组件有一些状态,比如加载数据、显示数据、没有数据。
<Card>
{ dataStatus === "Loaded" &&
<Card.Title>{person.Name}</Card.Title>
}
{ dataStatus === "Loading" &&
<Card.Loader>Loading...</Card.Loader>
}
{ dataStatus === "Error" &&
<Card.Error>Sorry, we had an oopsie...</Card.Error>
}
{ dataStatus === "Empty" &&
<Card.Empty>Looks like we're missing something...</Card.Empty>
}
</Card>
这里有进一步的解释和代码示例:https://davidlozzi.com/2021/05/14/keeping-react-components-state-top-of-mind/