【问题标题】:React/Webpack/Django - Uncaught TypeError: Cannot read property 'XXX' of undefinedReact/Webpack/Django - 未捕获的类型错误:无法读取未定义的属性“XXX”
【发布时间】:2019-06-16 12:22:08
【问题描述】:

我正在尝试创建一个名为“提案”的 React 组件,它将呈现从 Django 后端接收到的信息的表格列表。

我正在使用 Reactable-Search component 来形成表格,但是当我尝试将 this.props.proposals 值(例如 id 和 proj_name)映射到表格单元格时,我一直收到错误 - 未捕获TypeError:无法读取未定义的属性“单元格”

真的不知道为什么,因为当我将 this.props.proposals 直接映射到典型 html 表格标签的渲染返回中时,它正在工作,即渲染后端数据正常。我还在其他情况下使用了带有映射的 Reactable-Search 组件,它运行良好。

this.props.proposals 的日志输出还显示了正确的对象数组...:

如果有人能把我推向正确的方向,我真的很感激,谢谢!

提案组件:

import React, { Component } from "react";
import { connect } from "react-redux";
import SearchTable from "reactable-search";
import { proposals } from "../actions";

class Proposals extends Component {
  componentDidMount() {
    this.props.fetchProposals();
  }
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    var rows = this.props.proposals.map(p => ({
      selected: this.state.selectedRow === p.id,
      onClick: () => {
        this.setState({ selectedRow: p.id });
      },
      cells: {
        "#": p.id,
        "Project Name": p.proj_name
      }
    }));

    return (
      <SearchTable
        showExportCSVBtn={true}
        searchPrompt="Type to search"
        rows={rows}
      />
    );
  }
}

const mapStateToProps = state => {
  return {
    proposals: state.proposals
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetchProposals: () => {
      dispatch(proposals.fetchProposals());
    }
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Proposals);

提案reducer:

const initialState = [];

export default function proposals(state = initialState, action) {
  switch (action.type) {
    case "FETCH_PROPOSALS":
      return [...action.proposals];

    default:
      return state;
  }
}

提案操作

export const fetchProposals = () => {
  return dispatch => {
    let headers = { "Content-Type": "application/json" };
    return fetch("/api/proposals/", { headers })
      .then(res => res.json())
      .then(proposals => {
        return dispatch({
          type: "FETCH_PROPOSALS",
          proposals
        });
      });
  };
};

【问题讨论】:

  • 你能把你的proposals减速机的initialState贴出来吗?尝试在render 方法中记录this.props.proposals,看看它是否真的打印了预期的输出。
  • 嗨 Eugene - 当我记录 this.props.proposals 时,它确实输出了预期的对象数组......我还添加了减速器和动作文件。谢谢

标签: javascript django reactjs mapping react-props


【解决方案1】:

问题是您正在异步请求提案,但 SearchTable 组件似乎不适用于空的初始提案对象。尝试传入一个空数组作为其 rows 属性,您将收到关于未定义对象的完全相同的错误消息。

要解决此问题,您需要在获取提案时显示加载指示器而不是 SearchTable。你的 reducer 应该看起来像这样,除了你还应该处理失败的情况:

const initialState = { isLoading: false, error: null, proposals: [] };

export default function proposals(state = initialState, action) {
  switch (action.type) {
    case "FETCH_PROPOSALS":
      return {
        ...state,
        isLoading: true
      };
    case "FETCH_PROPOSALS_SUCCESS":
      return {
        ...state,
        isLoading: false,
        proposals: action.proposals
      };
    case "FETCH_PROPOSALS_FAILURE":
      return {
        ...state,
        isLoading: false,
        error: action.error,
      };
    default:
      return state;
  }
}

然后,当 isLoading 处于活动状态时,组件应呈现活动指示器或加载状态或 SearchTable 以外的任何内容:

import React, { Component } from "react";
import { connect } from "react-redux";
import SearchTable from "reactable-search";
import { proposals } from "../actions";

class Proposals extends Component {
  componentDidMount() {
    this.props.fetchProposals();
  }
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    const { proposals, error, isLoading } = this.props;

    if (isLoading) {
      return <div>Loading...</div>;
    }
    if (error) {
      return <div>{error.message}</div>;
    }
    if (proposals.length === 0) {
      return <div>No proposals</div>;
    }

    var rows = proposals.map(p => ({
      selected: this.state.selectedRow === p.id,
      onClick: () => {
        this.setState({ selectedRow: p.id });
      },
      cells: {
        "#": p.id,
        "Project Name": p.proj_name
      }
    }));

    return (
      <SearchTable
        showExportCSVBtn={true}
        searchPrompt="Type to search"
        rows={rows}
      />
    );
  }
}

const mapStateToProps = state => {
  return {
    proposals: state.proposals.proposals,
    isLoading: state.proposals.isLoading,
    error: state.proposals.error,
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetchProposals: () => {
      dispatch(proposals.fetchProposals());
    }
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Proposals);

还有 thunk 动作:

export const fetchProposals = () => {
  return dispatch => {
    dispatch({type: "FETCH_PROPOSALS"});
    let headers = { "Content-Type": "application/json" };
    return fetch("/api/proposals/", { headers })
      .then(res => res.json())
      .then(proposals => {
        dispatch({
          type: "FETCH_PROPOSALS_SUCCESS",
          proposals
        });
      })
      .catch(error => {
        dispatch({
          type: "FETCH_PROPOSALS_FAILURE",
          error,
        });
      });
  };
};

【讨论】:

  • 哇 - 非常感谢您清晰及时的回复和解释。解决方法是对的!我整天都被困在这上面,干杯
猜你喜欢
  • 2018-12-08
  • 2018-04-21
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-25
  • 2021-12-22
相关资源
最近更新 更多