我正在构建一个网上商店,前端使用 ReactJS,后端使用 Spree (Ruby)。
Spree 提供 API将前端和后端相互连接的解决方案。
我正在尝试显示带有产品图片的产品,但 Spree 的 API 以特定方式设置,产品图片和产品不在同一对象中。
API 响应是:
{
(holds products)data: [],
(Holds product images)included:[],
}
我的目标是创建一个显示产品信息和产品图像的 ul。
我试图映射 my API link哪个
this.state.arrays.map((product) =>
product.data
)
它以数据对象响应,但我不能例如执行 product.data.name 因为它返回 undefined 响应
日志中的数据响应
ProductsList.js:28 PL
[undefined]
Index.js:42 productsData
{}
ProductsList.js:28 PL
[Array(5)]
0: Array(5)
0: {id: "5", type: "image", attributes: {…}}
1: {id: "4", type: "image", attributes: {…}}
2: {id: "1", type: "image", attributes: {…}}
3: {id: "3", type: "image", attributes: {…}}
4: {id: "2", type: "image", attributes: {…}}
length: 5
__proto__: Array(0)
length: 1
__proto__: Array(0)
产品索引页
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from "prop-types";
import ProductsList from "./products/ProductsList";
import axios from 'axios';
const REACT_VERSION = React.version;
const include = '?include=images';
const API = 'https://stern-telecom-react-salman15.c9users.io/api/v2/storefront/products' + include;
const styles = {
card: {
maxWidth: 345,
},
media: {
height: 140,
},
};
class Index extends React.Component {
constructor(props){
super(props);
this.state = {
products: [],
productsData: {},
isLoading: false,
error: null,
};
}
componentDidMount() {
this.setState({ isLoading: true });
axios.get(API)
.then(result => this.setState({
products: result.data.data,
productsData: result.data,
isLoading: false,
}))
.catch(error => this.setState({
error,
isLoading: false
}));
// console.log(
// 'productsData',
// this.state.productsData
// )
}
render() {
const { products, productsData,isLoading, error } = this.state;
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<React.Fragment>
<h1>React version: {REACT_VERSION}</h1>
<ProductsList products={this.state.productsData}/>
</React.Fragment>
);
}
}
ProductsList.propTypes = {
greeting: PropTypes.string
};
export default Index
产品列表页面
import React from "react"
import PropTypes from "prop-types"
import { withStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
const url = "https://stern-telecom-react-salman15.c9users.io"
class ProductsList extends React.Component {
constructor(props) {
super(props);
const { products } = this.props;
const arrays = Object.values( {products} );
this.state = {
products,
arrays
};
}
render () {
return (
<React.Fragment>
<ul>
<p>Shop Products</p>
{
// console.log(
// 'PL',
// this.state.arrays.map((product) =>
// product.data
// )
// )
this.state.arrays.map(product =>
<li key={product.objectID}>
<Card>
<CardActionArea>
<CardMedia
image= {url + ''}
title={product.data.attributes.name}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{product.data.attributes.name}
</Typography>
<Typography component="p">
{product.data.attributes.description}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary">
{product.data.attributes.display_price}
</Button>
<Button size="small" color="primary">
add to cart
</Button>
</CardActions>
</Card>
</li>
)
}
</ul>
</React.Fragment>
);
}
}
ProductsList.propTypes = {
greeting: PropTypes.string
};
export default ProductsList
我希望得到的结果是产品信息和图片
最佳答案
获取 json 数据后的操作是错误的。返回结果是一个带有data的json对象属性,这是您要传递并获取产品的数组。
你要么通过 products至 <ProductsList>组件:
const { products, images, isLoading, error } = this.state;
...
<ProductsList products={products} images={images}/>
然后直接使用:
class ProductsList extends React.Component {
constructor(props) {
super(props);
const { products, images } = this.props;
this.state = {
products,
images
};
...
}
...
}
或使用 props.products.data直接获取里面的产品数组 ProductsList构造函数:
class ProductsList extends React.Component {
constructor(props) {
super(props);
const products = this.props.products.data;
const images = this.props.products.included;
...
}
...
}
不需要使用 const arrays = Object.values({ products });因为您已经有了包含产品的数组:
...
products: result.data.data, // products is an array with products
images: result.data.included, // images is an array with all posible images
productsData: result.data, // productsData.data is an array with products
...
此外,产品对象不包含任何名为 data 的属性:
<Typography gutterBottom variant="h5" component="h2">
{product.data.attributes.name}
</Typography>
<Typography component="p">
{product.data.attributes.description}
</Typography>
你必须像这样直接访问它的属性:
<Typography gutterBottom variant="h5" component="h2">
{product.attributes.name}
</Typography>
<Typography component="p">
{product.attributes.description}
</Typography>
编辑
这是一个CodeSandbox project简化代码,无需调用 Axios 请求(因为 it's restrticted ),而是将数据保存在 JSON 文件中。您还应该初始化 isLoading为真,或使 Index组件在有一些数据之前不渲染:
class Index extends React.Component {
constructor(props){
super(props);
this.state = {
...
isLoading: true,
}
}
}
这是一个更新的屏幕截图,它可以正常工作:
和简化的<ProductsList/>组件:
import React from "react";
const url = "https://stern-telecom-react-salman15.c9users.io";
class ProductsList extends React.Component {
constructor(props) {
super(props);
const { products, images } = this.props;
//const arrays = Object.values( {products} );
this.state = {
products,
images
//arrays
};
}
render() {
const { products, images } = this.state;
return (
<React.Fragment>
<p>Shop Products</p>
{console.log("PL", products, images)
// this.state.arrays.map(product =>
// <li key={product.objectID}>
// </li>
// )
}
<ul>
{products.map(product => (
<li key={product.key}>
<h4>{product.attributes.name}</h4>
<p>Description: {product.attributes.description}</p>
<p>Price: {product.attributes.display_price} </p>
<p>Images:</p>
<div>
{product.relationships.images.data.map(({ id }) => {
let image = images.find(image => image.id == id);
return image ? (
<img src={`${url}/${image.attributes.styles[1].url}`}/>
) : null;
})}
</div>
</li>
))}
</ul>
</React.Fragment>
);
}
}
export default ProductsList;
编辑 2
添加图像是一项非常简单的任务。您只需将产品数组与图像结合起来并显示图像。检查更新的 <ProductsList/>零件。当然你必须同时通过 products和 images至 <ProductsList/> (const images = productsData.included;)。检查更新的 CodeSandbox , <ProductsList/>组件和屏幕截图。
编辑 3
关于图像;每张图片都有一个 styles属性是不同大小的数组:
"included": [
{
"id": "5",
"type": "image",
"attributes": {
"viewable_type": "Spree::Variant",
"viewable_id": 4,
"styles": [
{
"url": "...",
"width": "48",
"height": "48"
},
{
"url": "...",
"width": "100",
"height": "100"
},
{
"url": "...",
"width": "240",
"height": "240"
},
{
"url": "...",
"width": "600",
"height": "600"
}
]
}
}
...
]
为了将图像映射到每个产品,我们必须使用 product.relationships.images.data 映射每个产品中存储的所有图像。这是一个带有 id 的对象数组和 type特性。对于产品图片中的每张图片,我们使用 let image = images.find(image => image.id == id) 搜索图片数组如果我们找到一张图片,那么我们会使用四种可用尺寸之一,或者可能使用所有可用尺寸( 48px 、 100px 、 240px 、 600px );我选择image.attributes.styles[1].url ,所以我显示可用图像尺寸的第二个元素,即 100px图片大小:
product.relationships.images.data.map(({ id }) => {
let image = images.find(image => image.id == id);
return image ? (
<img src={`${url}/${image.attributes.styles[1].url}`}/>
) : null;
})
编辑 4
如果您需要为每个产品获取一张图片,那么您可以使用一个函数来检查图片是否存在,然后从图片数组中获取图片:
// Here we're using an inline function to get the product image
// You can also create a normal class function and use that instead
{product.relationships.images.data.length > 0 &&
(() => {
// { id } is the destructure of product.relationships.images.data[0]
// which means it extract the property id to a stand alone variable
const { id } = product.relationships.images.data[0];
const image = images.find(image => image.id == id);
return image ? (
<img src={`${url}/${image.attributes.styles[1].url}`} />
) : null;
})()
}
这是一个隔离其内容并立即执行的内联函数:
(() => { ... })()
您可以阅读更多关于 Destructuring assignment
的信息({ id } = object)。
关于javascript - 如何使用多个对象映射 API [Spree API V2 & ReactJS],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55420885/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-