Проблема в том, что вы запрашиваете предложения асинхронно, но компонент SearchTable
, похоже, не работает с пустым объектом начальных предложений. Попробуйте передать пустой массив в качестве rows
prop, и вы получите точно такое же сообщение об ошибке для неопределенного объекта.
Чтобы это исправить, вам нужно показать индикатор загрузки вместо 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);
И громовой экшн:
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,
});
});
};
};