React / Webpack / Django - Uncaught TypeError: невозможно прочитать свойство XXX из undefined

Я пытаюсь создать компонент React под названием «Proposals», который будет отображать табличный список информации, полученной от бэкэнда Django.

Я использую компонент Reactable-Search для формирования таблицы, но продолжаю получать ошибка, когда я пытаюсь сопоставить значения this.props.proposals, такие как id и proj_name, с ячейками таблицы - Uncaught TypeError: Невозможно прочитать ячейки свойства undefined

На самом деле не уверен, почему, потому что, когда я отображаю this.props.proposals непосредственно в возвращении рендеринга типичных тегов таблицы html, он работает, то есть отображает данные серверной части в порядке. и я также использовал компонент Reactable-Search с сопоставлением в других случаях, и он работал нормально.

Вывод журнала this.props.proposals также показывает правильный массив объектов ...: screenshot

Очень признателен, если кто-то может подтолкнуть меня в правильном направлении, спасибо!

Компонент "Предложения":

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);

Редуктор предложений:

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
        });
      });
  };
};


person Community    schedule 23.01.2019    source источник
comment
Можете ли вы опубликовать initialState вашего proposals редуктора? Попробуйте зарегистрировать this.props.proposals в методе render и посмотрите, действительно ли он печатает ожидаемый результат.   -  person Eugene    schedule 23.01.2019
comment
Привет, Юджин - когда я регистрирую this.props.proposals, он выводит ожидаемый массив объектов ... Я также добавил файлы редуктора и действий. Благодарность   -  person    schedule 23.01.2019


Ответы (1)


Проблема в том, что вы запрашиваете предложения асинхронно, но компонент SearchTable, похоже, не работает с пустым объектом начальных предложений. Попробуйте передать в качестве rows пустой массив, и вы получите точно такое же сообщение об ошибке для неопределенного объекта.

Чтобы исправить это, вам нужно показывать индикатор загрузки вместо SearchTable во время загрузки предложений. Ваш редуктор должен выглядеть примерно так, за исключением того, что вы также должны обрабатывать случай сбоя:

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;
  }
}

Затем компонент должен отобразить индикатор активности или статус загрузки или что-то другое, кроме SearchTable, когда isLoading активен:

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,
        });
      });
  };
};
person Eugene    schedule 23.01.2019
comment
Вау - большое спасибо за четкий и быстрый ответ и объяснение. Решение верное! Я весь день застрял на этом, ура - person ; 23.01.2019