我有一个解析 JSON 的 redux 组件(在底部),但我不知道如何获取嵌套的子对象。我认为我没有正确理解 mapStateToProps 的工作原理。
控制台日志正在转储子对象,但是当我尝试访问 services.name 时,我得到了
“无法读取未定义的属性‘name’”
有人可以帮助我了解如何在此处映射属性吗?我在底部包含了一个我从 API 中获取的 JSON 示例。
服务列表.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
};
}
最佳答案
我假设您认为 this.props.fetchServices()
会更新 services
reducer,然后将 services
作为 prop 传递通过 mapStateToProps
。
如果这是正确的,请注意您正在 componentWillMount
中获取,这是一个BIG no no。
引自 componentWillMount
DOCS :
Avoid introducing any side-effects or subscriptions in this method.
您应该在 componentDidMount
中获取数据。
此外,您可能认为在从 ajax 请求中取回数据之前不会调用 render 方法。你看,React 不会等待你的 ajax 调用返回数据,无论如何都会调用 render
方法,所以第一个 render
调用会尝试map
到 services
的空数组(我假设你的 reducer 中有一个空数组作为初始状态)。
然后你的 renderServices
函数将得到一个空数组作为 data
并且 data.services
确实是 undefined
因此当你尝试访问 data.services.name
你得到错误:
"Cannot read property 'name' of undefined"
只需在渲染中使用一个条件:
<tbody>
{this.props.services && this.props.services.map(this.renderServices)}
</tbody>
编辑
作为您的评论的后续行动,您正在尝试在 object
上进行映射,但 .map
适用于数组。所以实际上你应该在 services.services.map(...)
而不是 services.map
上映射,尽管你仍然需要检查它是否存在。
我已经用你的代码做了一个工作示例,我没有包括 redux 和 ajax 请求,但我使用了你正在使用的相同数据,我只在 ServicesList
的第二次呈现上传递它,所以它基本上与您面临的情况相同。
我什至添加了一个超时来模拟延迟 + 添加了一个加载指示器来演示您可以(或应该)使用条件渲染做什么。
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"));
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
关于javascript - 带有嵌套 JSON 的 React/Redux mapStateToProps,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46455190/