javascript - 带有嵌套 JSON 的 React/Redux mapStateToProps

标签 javascript reactjs redux

我有一个解析 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 调用会尝试mapservices 的空数组(我假设你的 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/

相关文章:

javascript - 如何自动聚焦于 React 中的特定输入字段(单击另一个元素后)?

javascript - TypeError : React. PropTypes 在 React js 中未定义

reactjs - Redux:子操作后更新父组件数据

javascript - 如何将 dataurl 转换回图像并显示在 Canvas 上

javascript - 使javascript外部

javascript - React - 2路绑定(bind)文本输入,存储和显示的格式不同

forms - Redux 表单中的 DatePicker

Redux Toolkit - 将整个数组分配给 state

java - GWT 类成员命名

javascript - 无法读取未定义的属性 'Push' - Typescript