简体   繁体   English

使用 axios 调用在表 object 上呈现对象列表:呈现逻辑

[英]Render a list of objects on a table object using axios calls : Rendering logic

My component is supposed to render a list of driver in a table where it puts the diver name in the first column and the tractor number on the second column of each row.我的组件应该在表格中呈现驾驶员列表,其中将潜水员姓名放在第一列,将拖拉机编号放在每行的第二列。 However, if the reference to the driver table returns a null then it returns instead of the tractor number.但是,如果对驱动程序表的引用返回null ,那么它会返回而不是拖拉机编号。 <td><Link to ={`/assign-tractor/${driver.id}`}> Assign Tractor </Link></li>)</td>

how do I achieve this?我如何实现这一目标?

Below is what my what my code looks like in the back end and front end.下面是我的代码在后端和前端的样子。

I have a user table with has references to a tractor table我有一个用户表,其中包含对拖拉机表的引用

Model: Model:

public class User{
       @Id
       @GeneratedValue(strategy = GenerationType.AUTO)
       @Column(name ="user_id")
       private Long id;

       @OneToOne
       @JoinColumn(name = "tractor_id", referencedColumnName = "tractor_id")
       private Tractor tractor;

       @OneToOne
       @JoinColumn(name = "order_id", referencedColumnName = "order_id")
       private Order order;
} 


@Entity
@Table(name = "`order`")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="order_id")
    private Long id;

    private String orderNumber;
    }

@Entity
@Table(name = "tractor")
public class Tractor {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name ="tractor_id")
    private Long id;

    private String tractorNumber;

}

Controller: Controller:

       @CrossOrigin
       @RestController
       @RequestMapping("/user")
       public class UserController {
              private UserService userService;

          @Autowired
          public UserController(UserService userService) {
             super();
             this.userService = userService;
              }

              @GetMapping("drivers")
          public List<User> allDrivers() {
             return userService.findAllDriver();
          }

              @GetMapping("/id/{id}")
          public User getUserByUserId(@PathVariable long id) {
             return userService.findUserById(id);
          }

      }

      @CrossOrigin
      @RestController
      @RequestMapping("/tractor")
      public class TractorController {

         private TractorService tractorService;

         public TractorController(TractorService tractorService) {
            super();
            this.tractorService = tractorService;
         }

             @GetMapping("/tractors/{id}")
         public Tractor getTractorById(@PathVariable Long id) {
            return tractorService.FindTractorById(id).get();
         }
      }

React FrontEnd反应前端


import React, { useState,Component} from 'react'
import axios from 'axios'
import './assignment-table.css';
import {withRouter} from 'react-router-dom';

class AssignmentTable extends Component {

  constructor(props){
    super(props);
    this.state = {
      drivers : [],
      isLoggeIn: false,
      tractorNumber: ""
    }
  }
  componentDidMount(){
    axios.get(`http://localhost:3000/project/user/users`)
    .then(response => {
      console.log(response)
      this.setState({ drivers: response.data })
    })
    .catch( err => console.log(err))

//get tractor using user tractor reference, then assigns tractor number
/*  
axios.get(`http://localhost:3000/project/tractor/${users.tractor}`)
  .then(response => {
    console.log(response)
    this.setState({ tractorNumber: response.data.tractorNumber })
  })
  .catch( err => console.log(err))
}
*/
  render() {
    let drivers = this.state.drivers ? this.state.drivers.map((item, key) => {
   return (
   <tr>
   <td key = {key}>{item.firstName}  {item.lastName}</td>
    </tr>)
    }) : "No Avilable Driver"

    return (
            <table class="table">
              <thead>
                 <tr>
                  <th scope="col">Driver Name</th>
                  <th scope="col">Tractor</th>
                  <th scope="col">Order</th>
                </tr>
              </thead>

              <tbody>
                {drivers}
             </tbody>
             </table>
);
}
  }
export default withRouter (AssignmentTable);

the hard coded bootstrap version of what I am trying to replicate:我要复制的硬编码引导程序版本:


<!DOCTYPE html>
<html lang="en">
<head>
  <title>Bootstrap Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>

  <table class="table">
    <thead>
      <tr>
        <th scope="col">#</th>
        <th scope="col">Driver Name</th>
        <th scope="col">Tractor Number</th>
        <th scope="col">Order Number</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th scope="row">1</th>
        <td>Mark Otto</td>
        <td>123215</td>
        <td>89562</td>
      </tr>
      <tr>
        <th scope="row">2</th>
        <td>Jacob Thornton</td>
        <td>123254</td>
        <td>564232</td>
      </tr>
      <tr>
        <th scope="row">3</th>
        <td>Larry the Bird</td>
        <td><a href="#">Assign Tractor</a></td>
        <td><a href="#">Assign Order</a></td>
      </tr>
    </tbody>
  </table>
</body>
</html>

So there are several ways to solve this.所以有几种方法可以解决这个问题。

The "naive" way would be to make a request to your backend for each record, and then when that record comes back, display the information. “幼稚”的方法是为每条记录向您的后端发出请求,然后当该记录返回时,显示信息。 However, that is potentially a lot of "slow" requests, and browsers limit the number of requests that you can do at once.但是,这可能是很多“缓慢”的请求,并且浏览器限制了您一次可以执行的请求数量。 This type of query is called n+1 ( 2n+1 in your case) and is generally considered a bad thing from a performance perspective.这种类型的查询称为n+1 (在您的情况下2n+1 ),从性能的角度来看通常被认为是一件坏事。 But it can be done, and it is fairly easy.但这是可以做到的,而且相当容易。

The alternative to that would be to return the information needed to the front end with just one query.另一种方法是仅通过一个查询将所需的信息返回给前端。 So you would change your backend to include tractorNumber and orderNumber in the information provided by the user/users endpoint.因此,您将更改后端以在user/users端点提供的信息中包含tractorNumberorderNumber This makes the front end dead simple.这使得前端非常简单。

I would also consider actually using tractorNumber and orderNumber as the actual id's, if:我也会考虑实际使用tractorNumberorderNumber作为实际的 id,如果:

  • they were unique他们是独一无二的
  • they existed when the record was created and never changed它们在记录创建时就存在并且从未更改

Be careful that you don't just move your n+1 query to the backend, because then the slowness moves there (but it would probably still be faster).请注意,您不要只是将n+1查询移至后端,因为那样缓慢会移到那里(但它可能仍然会更快)。 When you lookup the information for the user endpoint, make sure that it is joining the order and tractor information as well, so that it is available without another lookup.当您查找用户端点的信息时,请确保它也加入了订单和拖拉机信息,以便无需再次查找即可使用。

The reason you may not want to change your backend is that it kinda makes the data less "pure", as now your endpoints are returning data for multiple models at once.您可能不想更改后端的原因是它有点让数据变得不那么“纯粹”,因为现在您的端点正在同时返回多个模型的数据。 And sometimes you just can't change the backend for whatever reason.有时无论出于何种原因,您都无法更改后端。 You might also decide that this view deserves it's own special endpoint.您可能还决定此视图值得拥有自己的特殊端点。

Another solution that might work is getting a list of all tractor and order information on the front end and storing that so that you can look at that cached information instead of asking the backend each time.另一个可能有效的解决方案是在前端获取所有拖拉机和订单信息的列表并将其存储,以便您可以查看缓存的信息,而不是每次都询问后端。 But the downside of that is that you have to store all the tractor and order info, and that could be a lot.但缺点是您必须存储所有拖拉机和订单信息,这可能会很多。 If you decide to "paginate" your backend results, then this solution becomes especially difficult, but might work.如果您决定对后端结果进行“分页”,那么此解决方案将变得特别困难,但可能会奏效。

If you do decide to go with the "naive" approach, I'd recommend extracting each row into a component and then have it have it's own lookup, for example:如果您确实决定使用“天真”方法 go,我建议将每一行提取到一个组件中,然后让它有自己的查找,例如:

 function getDrivers(){ // this would be the response in the real case /** return axios.get(`http://localhost:3000/project/user/users`).then(response => { console.log('drivers request:', response) return response.data }) */ // fake response for example return new Promise((resolve) => setTimeout(() => resolve([ {id: 11, firstName: "Dell", lastName: "McDonald", tractor_id: 123, order_id: 234}, {id: 12, firstName: "Bob", lastName: "Crockett", tractor_id: 145, order_id: 245}, {id: 13, firstName: "Joe", lastName: "Fresh", tractor_id: null, order_id: null} ]), 1000)) } function getTractorNumber(tractor_id) { //get tractor using user tractor reference, then assigns tractor number /* axios.get(`http://localhost:3000/project/tractor/${tractor_id}`).then(response => { console.log("tractor request:", response) return response.data.tractorNumber }) */ //Fake tractor response return new Promise((resolve) => setTimeout(() => resolve(`#T${tractor_id}-00`), Math.random()*5000)) } function getOrderNumber(order_id) { /* axios.get(`http://localhost:3000/project/order/${order_id}`).then(response => { console.log("order request:", response) return response.data.tractorNumber }) */ //Fake order response return new Promise((resolve) => setTimeout(() => resolve(`#O${order_id}`), Math.random()*5000)) } class AssignmentTable extends React.Component { constructor(props){ super(props); this.state = { drivers: [] } } componentDidMount(){ getDrivers().then(drivers => { this.setState({ drivers }) }).catch( err => console.log(err)) } render() { let drivers = this.state.drivers.length? this.state.drivers.map((item) => { return (<DriverRow driver={item} key={item.id} />) }): "No Available Drivers" return ( <table class="table"> <thead> <tr> <th scope="col">Driver Name</th> <th scope="col">Tractor</th> <th scope="col">Order</th> </tr> </thead> <tbody> {drivers} </tbody> </table> ); } } class DriverRow extends React.Component { constructor(...args) { super(...args) this.state = { tractorNumber: "loading...", orderNumber: "loading..." } } componentDidMount(){ getTractorNumber(this.props.driver.tractor_id).then(tractorNumber => { this.setState({ tractorNumber }) }).catch( err => console.log(err)) getOrderNumber(this.props.driver.order_id).then(orderNumber => { this.setState({ orderNumber }) }).catch( err => console.log(err)) } render() { const {firstName, lastName, tractor_id, order_id} = this.props.driver return (<tr> <td>{firstName} {lastName}</td> <td>{tractor_id? this.state.tractorNumber: <a href="#">Assign Tractor</a>}</td> <td>{order_id? this.state.orderNumber: <a href="#">Assign Order</a>}</td> </tr>) } } ReactDOM.render(<AssignmentTable />, document.getElementById('main'))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <main id="main"/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM