我有一个正在解析JSON的redux组件(在底部),但我无法弄清楚如何抓取嵌套的子对象。我不认为我正确理解mapStateToProps是如何工作的。
控制台日志正在转储子对象,但是当我尝试访问services.name时,我得到了
"Cannot read property 'name' of undefined"
有人可以帮我理解如何在这里映射属性吗?我已经从底部的API中抓取了一个JSON示例。
服务 - list.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../actions';
class ServicesList extends Component {
componentDidMount(){
this.props.fetchServices();
}
render() {
//console.log('render called in ServicesList component');
return (
<table className='table table-hover'>
<thead>
<tr>
<th>Service Name</th>
</tr>
</thead>
<tbody>
{this.props.services.map(this.renderServices)}
</tbody>
</table>
);
}
renderServices(data) {
console.log(data.services);
const name = data.services.name;
return(
<tr key={name}>
<td>{name}</td>
</tr>
);
}
}
function mapStateToProps({services}) {
return { services };
}
export default connect(mapStateToProps, actions)(ServicesList);
我的JSON看起来像这样:
{
"services": [
{
"name": "redemption-service",
"versions": {
"desired": "20170922_145033",
"deployed": "20170922_145033"
},
"version": "20170922_145033"
}, {
"name": "client-service",
"versions": {
"desired": "20170608_094954",
"deployed": "20170608_094954"
},
"version": "20170608_094954"
}, {
"name": "content-rules-service",
"versions": {
"desired": "20170922_130454",
"deployed": "20170922_130454"
},
"version": "20170922_130454"
}
]
}
最后,我有一个公开axios.get的动作:
import axios from 'axios';
const ROOT_URL=`http://localhost:8080/services.json`;
export const FETCH_SERVICES = 'FETCH_SERVICES';
export function fetchServices(){
const url = `${ROOT_URL}`;
const request = axios.get(url);
return{
type: FETCH_SERVICES,
payload: request
};
}
答案 0 :(得分:2)
我认为您认为this.props.fetchServices()
会更新services
减速器,然后通过services
将mapStateToProps
作为道具传递。
如果这是正确的,请注意您在componentWillMount
内取货,这是一个 BIG no no。
引自componentWillMount
DOCS:
避免在此方法中引入任何副作用或订阅。
您应该在componentDidMount
中获取数据。
此外,您可能认为在从ajax请求获取数据之前,不会调用render方法。你知道,反应不会等待你的ajax调用以获取数据,无论如何都会调用render
方法,所以第一个render
调用会尝试{{1在map
的空数组上(你假设你的减速器中有一个空数组作为初始状态)。
然后,您的services
函数将获得一个空数组renderServices
,而data
确实为data.services
,因此当您尝试访问undefined
时会出现错误:
&#34;无法读取属性&#39; name&#39;未定义&#34;
只需在渲染中使用条件:
data.services.name
修改强>
作为评论的后续内容,您尝试在<tbody>
{this.props.services && this.props.services.map(this.renderServices)}
</tbody>
上进行映射,但object
在数组上工作。实际上你应该在.map
而不是services.services.map(...)
上进行映射,尽管你还需要检查它是否存在。
我已经使用您的代码制作了一个工作示例,我没有包含redux和ajax请求,但我使用了您正在使用的相同数据,并且我只在services.map
的第二个渲染上传递它,所以它基本上与你面临的情况相同。
我甚至添加了超时来模仿延迟+添加了一个加载指示器来演示你可以(或应该)使用条件渲染做什么。
ServicesList
&#13;
const fakeData = {
services: [
{
name: "redemption-service",
versions: {
desired: "20170922_145033",
deployed: "20170922_145033"
},
version: "20170922_145033"
},
{
name: "client-service",
versions: {
desired: "20170608_094954",
deployed: "20170608_094954"
},
version: "20170608_094954"
},
{
name: "content-rules-service",
versions: {
desired: "20170922_130454",
deployed: "20170922_130454"
},
version: "20170922_130454"
}
]
};
class ServicesList extends React.Component {
componentDidMount() {
this.props.fetchServices();
}
render() {
const { services } = this.props;
return (
<table className="table table-hover">
<thead>
<tr>
<th>Service Name</th>
</tr>
</thead>
<tbody>
{services.services ? (
services.services.map(this.renderServices)
) : (
this.renderLoader()
)}
</tbody>
</table>
);
}
renderLoader() {
return (
<tr>
<td>Loading...</td>
</tr>
);
}
renderServices(data) {
const name = data.name;
return (
<tr key={name}>
<td>{name}</td>
</tr>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {}
};
this.fetchServices = this.fetchServices.bind(this);
}
fetchServices() {
setTimeout(() => {
this.setState({ data: { ...fakeData } });
}, 1500);
}
render() {
const { data } = this.state;
return (
<div>
<ServicesList services={data} fetchServices={this.fetchServices} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
&#13;