无法读取React应用中未定义的属性“地图”

时间:2019-12-27 15:05:51

标签: javascript reactjs

我正在尝试开发一个简单的React应用程序,它具有Crud操作,但是我什至无法列出存储在sql数据库中的对象。我在前端遵循以下示例:https://github.com/only2dhir/react-js-example 然后我继续进行,为我的对象添加了组件。

在我的申请中,我有医生和患者。将患者分配给医生,因此医生可以有一个或多个患者。为此,我创建了我的jsx文件ListCaregiverComponent.jsx:

import React, { Component } from 'react'
import ApiServiceCaregiver from "../../service/ApiServiceCaregiver";
import ApiServicePatient from "../../service/ApiServicePatient";

import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Typography from '@material-ui/core/Typography';

class ListCaregiverComponent extends Component {

    constructor(props) {
        super(props)
        this.state = {
            caregivers: [],
            patients: [],
            message: null
        }
        this.deleteCaregiver = this.deleteCaregiver.bind(this);
        this.editCaregiver = this.editCaregiver.bind(this);
        this.addCaregiver = this.addCaregiver.bind(this);
        this.reloadCaregiverList = this.reloadCaregiverList.bind(this);
        this.reloadPatientList = this.reloadPatientList.bind(this);
    }

    componentDidMount() {
        this.reloadCaregiverList();
        this.reloadPatientList();
    }

    reloadCaregiverList() {
        ApiServiceCaregiver.fetchCaregivers()
            .then((res) => {
                this.setState({caregivers: res.data.result})
            });
    }

    reloadPatientList() {
        ApiServicePatient.fetchPatients()
            .then((res) => {
                this.setState({patients: res.data.result})
            });
    }

    deleteCaregiver(userId) {
        ApiServiceCaregiver.deleteCaregiver(userId)
            .then(res => {
                this.setState({message : 'User deleted successfully.'});
                this.setState({caregivers: this.state.caregivers.filter(user => user.id !== userId)});
            })

    }

    editCaregiver(id) {
        window.localStorage.setItem("userId", id);
        this.props.history.push('/edit-caregiver');
    }

    addCaregiver() {
        window.localStorage.removeItem("userId");
        this.props.history.push('/add-caregiver');
    }

    render() {
        return (
            <div>
                <br></br>
                <br></br>
                <Typography variant="h4" style={style}>Caregiver Details</Typography>


                <br></br>
                <br></br>
                <Table>
                    <TableHead>
                        <TableRow>
                            <TableCell>Id</TableCell>
                            <TableCell align="right">Name</TableCell>
                            <TableCell align="right">Birth Date</TableCell>
                            <TableCell align="right">Gender</TableCell>
                            <TableCell align="right">Address</TableCell>
                            <TableCell align="center">Patients</TableCell>
                        </TableRow>
                    </TableHead>

                    <TableBody>
                        {this.state.caregivers.map(({ id, name, birthDate, gender, address, patients = [] }) =>(
                            <TableRow key={id}>
                                <TableCell component="th" scope="row">
                                    {id}
                                </TableCell>
                                <TableCell align="right">{name}</TableCell>
                                <TableCell align="right">{birthDate}</TableCell>
                                <TableCell align="right">{gender}</TableCell>
                                <TableCell align="right">{address}</TableCell>
                                <TableCell align="right">
                                    <TableRow>
                                        <TableCell align = "right" >Id</TableCell>
                                        <TableCell align = "right" >Name</TableCell>
                                        <TableCell align="right">Birth Date</TableCell>
                                        <TableCell align="right">Gender</TableCell>
                                        <TableCell align="right">Address</TableCell>
                                        <TableCell align="right">Medical Record</TableCell>
                                    </TableRow>
                                {patients.map(({ id, name, birthDate, gender, address, medicalRecord })=> {
                                    return (
                                        <TableRow key={id}>
                                            <TableCell component="th" scope="row">
                                                {id}
                                            </TableCell>
                                            <TableCell align="right">{name}</TableCell>
                                            <TableCell align="right">{birthDate}</TableCell>
                                            <TableCell align="right">{gender}</TableCell>
                                            <TableCell align="right">{address}</TableCell>
                                            <TableCell align="right">{medicalRecord}</TableCell>
                                        </TableRow>
                                    )
                                })}
                                </TableCell>
                            </TableRow>
                        ))}
                    </TableBody>
                </Table>
            </div>
        );
    }

}

const style ={
    display: 'flex',
    justifyContent: 'center'
}

export default ListCaregiverComponent;

ListPatientComponent.jsx看起来像这样:

import React, { Component } from 'react'
import ApiServicePatient from "../../service/ApiServicePatient";

import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Typography from '@material-ui/core/Typography';

class ListPatientComponent extends Component {

    constructor(props) {
        super(props)
        this.state = {
            patients: [],
            message: null
        }
        this.deletePatient = this.deletePatient.bind(this);
        this.editPatient = this.editPatient.bind(this);
        this.addPatient = this.addPatient.bind(this);
        this.reloadPatientList = this.reloadPatientList.bind(this);
    }

    componentDidMount() {
        this.reloadPatientList();
    }

    reloadPatientList() {
        ApiServicePatient.fetchPatients()
            .then((res) => {
                this.setState({patients: res.data.result})
            });
    }

    deletePatient(userId) {
        ApiServicePatient.deletePatient(userId)
            .then(res => {
                this.setState({message : 'User deleted successfully.'});
                this.setState({patients: this.state.patients.filter(user => user.id !== userId)});
            })

    }

    editPatient(id) {
        window.localStorage.setItem("userId", id);
        this.props.history.push('/edit-patient');
    }

    addPatient() {
        window.localStorage.removeItem("userId");
        this.props.history.push('/add-patient');
    }

    render() {
        return (
            <div>
                <br></br>
                <br></br>
                <Typography variant="h4" style={style}>Patient Details</Typography>


                <br></br>
                <br></br>
                <Table>
                    <TableHead>
                        <TableRow>
                            <TableCell>Id</TableCell>
                            <TableCell align="right">Name</TableCell>
                            <TableCell align="right">Birth Date</TableCell>
                            <TableCell align="right">Gender</TableCell>
                            <TableCell align="right">Address</TableCell>
                            <TableCell align="right">Medical Record</TableCell>
                            <TableCell align="center">Medication Plans</TableCell>
                        </TableRow>
                    </TableHead>

                    <TableBody>
                        {this.state.patients.map(row => (
                            <TableRow key={row.id}>
                                <TableCell component="th" scope="row">
                                    {row.id}
                                </TableCell>
                                <TableCell align="right">{row.name}</TableCell>
                                <TableCell align="right">{row.birthDate}</TableCell>
                                <TableCell align="right">{row.gender}</TableCell>
                                <TableCell align="right">{row.address}</TableCell>
                                <TableCell align="right">{row.medicalRecord}</TableCell>

                            </TableRow>
                        ))}
                    </TableBody>
                </Table>
            </div>
        );
    }

}

const style ={
    display: 'flex',
    justifyContent: 'center'
}

export default ListPatientComponent;

,并且有效。

我还添加了两个新的js文件ApiServicePatient.js和ApiServiceCaregiver.js:

import axios from 'axios';

const CAREGIVER_API_BASE_URL = 'http://localhost:8080/caregivers';

class ApiServiceCaregiver {

    fetchCaregivers() {
        return axios.get(CAREGIVER_API_BASE_URL);
    }

    fetchCaregiverById(caregiverId) {
        return axios.get(CAREGIVER_API_BASE_URL + '/' + caregiverId);
    }

    deleteCaregiver(caregiverId) {
        return axios.delete(CAREGIVER_API_BASE_URL + '/' + caregiverId);
    }

    addCaregiver(caregiver) {
        return axios.post(""+CAREGIVER_API_BASE_URL, caregiver);
    }

    editCaregiver(caregiver) {
        return axios.put(CAREGIVER_API_BASE_URL + '/' + caregiver.id, caregiver);
    }

}

export default new ApiServiceCaregiver();
import axios from 'axios';

const PATIENT_API_BASE_URL = 'http://localhost:8080/patients';

class ApiServicePatient {

    fetchPatients() {
        return axios.get(PATIENT_API_BASE_URL);
    }

    fetchPatientById(userId) {
        return axios.get(PATIENT_API_BASE_URL + '/' + userId);
    }

    deletePatient(userId) {
        return axios.delete(PATIENT_API_BASE_URL + '/' + userId);
    }

    addPatient(user) {
        return axios.post(""+PATIENT_API_BASE_URL, user);
    }

    editPatient(user) {
        return axios.put(PATIENT_API_BASE_URL + '/' + user.id, user);
    }

}

export default new ApiServicePatient();

此外,在App.js中,我添加了:

import React from 'react';
import './App.css';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import ListUserComponent from "./component/user/ListUserComponent";
import AddUserComponent from "./component/user/AddUserComponent";
import EditUserComponent from "./component/user/EditUserComponent";

import ListPatientComponent from "./component/patient/ListPatientComponent";
import ListCaregiverComponent from "./component/caregiver/ListCaregiverComponent";

function App() {
  return (
      <div className="container">
          <Router>
              <div className="col-md-6">
                  <h1 className="text-center" style={style}>React User Application</h1>
                  <Switch>
                      <Route path="/" exact component={ListUserComponent} />
                      <Route path="/users" component={ListUserComponent} />
                      <Route path="/add-user" component={AddUserComponent} />
                      <Route path="/edit-user" component={EditUserComponent} />

                      <Route path="/patients" component={ListPatientComponent} />

                      <Route path="/caregivers" component={ListCaregiverComponent} />
                  </Switch>
              </div>
          </Router>
      </div>
  );
}

const style = {
    color: 'red',
    margin: '10px'
}

export default App;

它不起作用,只会显示:

Unhandled Rejection (TypeError): Cannot read property 'map' of undefined

并以:

指示行
<TableCell align="right">{row.address}</TableCell>
 {row.patients.map(row => (

在后端应用程序中,类Caregiver具有一个患者对象列表,映射为一对多:

    @OneToMany(mappedBy = "caregiver", fetch = FetchType.EAGER)
    private List<Patient> patients;

有人有建议吗?

--------在第一个答案后更新---------

我不再遇到该错误,但是我无法在护理人员表中显示分配的患者。对于每个护理人员的患者,对应的TableCell均为空。为什么会这样?

4 个答案:

答案 0 :(得分:2)

您先做this.state.caregivers.map(row =>,然后再做{row.patients.map(row =>,但我看不到任何迹象表明每个caregivers元素都有一个patients数组属性

答案 1 :(得分:1)

由于您正在使用异步调用,因此javascript开始渲染,并且在短短的几毫秒之内,“ this.state.caregivers”没有任何值,因此您无法映射空值,因此它必须为空数组。

确保添加条件以首先检查或在构造函数中将“ this.state.caregivers”声明为空数组。

答案 2 :(得分:0)

尝试在每张地图之前添加要映射的属性,并&&这样

this.state.caregivers && this.state.caregivers.map

对代码中的每个地图执行此操作。

希望这会有所帮助

答案 3 :(得分:0)

如其他答案所述,对于某些行,patients可能是未定义的,因此您可以使用default value为它分配一个Destructuring

{this.state.caregivers.map(({ id, name, birthDate, gender, address, patients = [] }) => (
  <TableCell component="th" scope="row">
     {id}
  </TableCell>
  <TableCell align="right">{name}</TableCell>
  <TableCell align="right">{birthDate}</TableCell>
  <TableCell align="right">{gender}</TableCell>
  <TableCell align="right">{address}</TableCell>

  {patients.map(row => (
   ...