Javascript 上下文API中的ReactJS异步axios
我从Javascript 上下文API中的ReactJS异步axios,javascript,reactjs,async-await,axios,Javascript,Reactjs,Async Await,Axios,我从context.js中的RESTAPI获取数据。我将数据分配给state。以下是context.js中的代码: export class AppProvider extends Component { state = { products: [], cart: [], dispatch: action => this.setState(state => reducer(state, action)) } f
context.js
中的RESTAPI获取数据。我将数据分配给state。以下是context.js
中的代码:
export class AppProvider extends Component {
state = {
products: [],
cart: [],
dispatch: action => this.setState(state => reducer(state, action))
}
fetchData = async () => {
const products = await axios.get('http://127.0.0.1:4000/product/all', { headers: { "Access-Control-Allow-Origin": "*" } })
this.setState({
products: products.data
})
}
componentDidMount(){
this.fetchData();
}
render() {
return (
<AppContext.Provider value={this.state}>
{this.props.children}
</AppContext.Provider>
)
}
}
您的
AppProvider
组件是正确的,唯一的问题是您从API获取结果,然后在componentDidMount
中执行该操作,而该组件应该是正确的
但是,当您刷新页面时,AppProvider
中的设置将重置为初始值,并且由于您已经在ProductDetail
组件上,因此您甚至在API请求提供产品值之前就尝试访问产品值,因此
const filteredProduct = products.filter(p => p.id == props.match.params.id)
将返回您可以清空的数组
出现此问题的原因是您试图访问filteredProduct[0]。image
和类似的其他属性
这里的解决方案是使用loadingState并呈现loader,直到数据可用为止
另外,请确保数据可用时,filteredProduct
永远不会为空
export class AppProvider extends Component {
state = {
isLoading: true,
products: [],
cart: [],
dispatch: action => this.setState(state => reducer(state, action))
}
fetchData = async () => {
const products = await axios.get('http://127.0.0.1:4000/product/all', { headers: { "Access-Control-Allow-Origin": "*" } })
this.setState({
isLoading: false,
products: products.data
})
}
componentDidMount(){
this.fetchData();
}
render() {
return (
<AppContext.Provider value={this.state}>
{this.props.children}
</AppContext.Provider>
)
}
}
导出类AppProvider扩展组件{
状态={
孤岛加载:是的,
产品:[],
购物车:[],
dispatch:action=>this.setState(state=>reducer(state,action))
}
fetchData=async()=>{
const products=等待axios.get('http://127.0.0.1:4000/product/all“,{标头:{“访问控制允许源”:“*”})
这是我的国家({
孤岛加载:false,
产品:产品数据
})
}
componentDidMount(){
这是fetchData();
}
render(){
返回(
{this.props.children}
)
}
}
在产品细节方面
const ProductDetail = props => {
const [inputValue, setInputValue] = useState(1);
const preventNegative = e => {
const value = e.target.value.replace(/[^\d]/, '');
if (parseInt(value) !== 0) {
setInputValue(value);
}
}
const addToCart = (e, productID) => {
// eslint-disable-next-line array-callback-return
const product = products.filter(p => {
// eslint-disable-next-line eqeqeq
if (p.id == productID) {
return p
}
})
console.log(product);
dispatch({
type: 'ADD_TO_CART',
payload: [product, inputValue]
})
toast.success("The product has been added to cart successfully !", {
position: toast.POSITION.TOP_CENTER,
autoClose: 2500,
transition: Slide
})
}
const { products, dispatch, isLoading } = useContext(AppContext)
if(isLoading) return <div>Loading...</div>
const filteredProduct = products.filter(p => p.id == props.match.params.id)
return (
<React.Fragment>
<main className="mt-5 pt-4">
<div className="container dark-grey-text mt-5">
<div className="row wow fadeIn">
<div className="col-md-6 mb-4">
<img src={filteredProduct[0].image} className="img-fluid" alt="" />
</div>
<div className="col-md-6 mb-4">
<div className="p-4">
<div className="mb-3">
<Badge color="primary">New</Badge>
<Badge color="success">Best seller</Badge>
<Badge color="danger">{filteredProduct[0].discountRate}% OFF</Badge>
</div>
<h2 className="h2">{filteredProduct[0].title}</h2>
<p className="lead">
<span className="mr-1">
<del>${filteredProduct[0].prevPrice}</del>
</span>
<span>${filteredProduct[0].price}</span>
</p>
<p className="text-muted">
{filteredProduct[0].detail}
</p>
<form className="d-flex justify-content-left">
<input
min="1"
onChange={(e) => preventNegative(e)}
value={inputValue}
type="number"
aria-label="Search"
className="form-control"
style={{ width: '100px' }} />
<Button onClick={(e) => addToCart(e, filteredProduct[0].id)} color="primary">Add to Cart <FontAwesomeIcon icon={faShoppingCart} /> </Button>
</form>
</div>
</div>
</div>
</div>
</main>
</React.Fragment>
)
}
export default ProductDetail;
constproductdetail=props=>{
常量[inputValue,setInputValue]=useState(1);
const prevent negative=e=>{
const value=e.target.value.replace(/[^\d]/,“”);
if(parseInt(值)!==0){
设置输入值(值);
}
}
const addToCart=(e,productID)=>{
//eslint禁用下一行数组回调返回
const product=products.filter(p=>{
//eslint禁用下一行EQEQ
if(p.id==productID){
返回p
}
})
控制台日志(产品);
派遣({
键入:“将\添加到\购物车”,
有效负载:[产品,输入值]
})
toast.success(“产品已成功添加到购物车!”{
位置:toast.position.TOP_居中,
自动关闭:2500,
过渡:幻灯片
})
}
const{products,dispatch,isLoading}=useContext(AppContext)
如果(正在加载)返回加载。。。
const filteredProduct=products.filter(p=>p.id==props.match.params.id)
返回(
新的
畅销书
{filteredProduct[0]。取消集中度}%OFF
{filteredProduct[0]。标题}
${filteredProduct[0]。prevPrice}
${filteredProduct[0]。价格}
{filteredProduct[0]。详细信息}
(e)}
值={inputValue}
type=“编号”
aria label=“搜索”
className=“表单控件”
样式={{width:'100px'}}/>
addToCart(e,filteredProduct[0].id)}color=“primary”>添加到购物车
)
}
导出默认ProductDetail;
get请求的解析是否正确?如果您在设置状态之前登录产品,它看起来正确吗?页面刷新的预期行为是什么??将数据保存在localstorage中,并从中初始化。
const ProductDetail = props => {
const [inputValue, setInputValue] = useState(1);
const preventNegative = e => {
const value = e.target.value.replace(/[^\d]/, '');
if (parseInt(value) !== 0) {
setInputValue(value);
}
}
const addToCart = (e, productID) => {
// eslint-disable-next-line array-callback-return
const product = products.filter(p => {
// eslint-disable-next-line eqeqeq
if (p.id == productID) {
return p
}
})
console.log(product);
dispatch({
type: 'ADD_TO_CART',
payload: [product, inputValue]
})
toast.success("The product has been added to cart successfully !", {
position: toast.POSITION.TOP_CENTER,
autoClose: 2500,
transition: Slide
})
}
const { products, dispatch, isLoading } = useContext(AppContext)
if(isLoading) return <div>Loading...</div>
const filteredProduct = products.filter(p => p.id == props.match.params.id)
return (
<React.Fragment>
<main className="mt-5 pt-4">
<div className="container dark-grey-text mt-5">
<div className="row wow fadeIn">
<div className="col-md-6 mb-4">
<img src={filteredProduct[0].image} className="img-fluid" alt="" />
</div>
<div className="col-md-6 mb-4">
<div className="p-4">
<div className="mb-3">
<Badge color="primary">New</Badge>
<Badge color="success">Best seller</Badge>
<Badge color="danger">{filteredProduct[0].discountRate}% OFF</Badge>
</div>
<h2 className="h2">{filteredProduct[0].title}</h2>
<p className="lead">
<span className="mr-1">
<del>${filteredProduct[0].prevPrice}</del>
</span>
<span>${filteredProduct[0].price}</span>
</p>
<p className="text-muted">
{filteredProduct[0].detail}
</p>
<form className="d-flex justify-content-left">
<input
min="1"
onChange={(e) => preventNegative(e)}
value={inputValue}
type="number"
aria-label="Search"
className="form-control"
style={{ width: '100px' }} />
<Button onClick={(e) => addToCart(e, filteredProduct[0].id)} color="primary">Add to Cart <FontAwesomeIcon icon={faShoppingCart} /> </Button>
</form>
</div>
</div>
</div>
</div>
</main>
</React.Fragment>
)
}
export default ProductDetail;