[英]Render a list of objects on a table object using axios calls : Rendering logic
我的组件应该在表格中呈现驾驶员列表,其中将潜水员姓名放在第一列,将拖拉机编号放在每行的第二列。 但是,如果对驱动程序表的引用返回null
,那么它会返回而不是拖拉机编号。 <td><Link to ={`/assign-tractor/${driver.id}`}> Assign Tractor </Link></li>)</td>
我如何实现这一目标?
下面是我的代码在后端和前端的样子。
我有一个用户表,其中包含对拖拉机表的引用
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:
@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();
}
}
反应前端
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);
我要复制的硬编码引导程序版本:
<!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>
所以有几种方法可以解决这个问题。
“幼稚”的方法是为每条记录向您的后端发出请求,然后当该记录返回时,显示信息。 但是,这可能是很多“缓慢”的请求,并且浏览器限制了您一次可以执行的请求数量。 这种类型的查询称为n+1
(在您的情况下2n+1
),从性能的角度来看通常被认为是一件坏事。 但这是可以做到的,而且相当容易。
另一种方法是仅通过一个查询将所需的信息返回给前端。 因此,您将更改后端以在user/users
端点提供的信息中包含tractorNumber
和orderNumber
。 这使得前端非常简单。
我也会考虑实际使用tractorNumber
和orderNumber
作为实际的 id,如果:
请注意,您不要只是将n+1
查询移至后端,因为那样缓慢会移到那里(但它可能仍然会更快)。 当您查找用户端点的信息时,请确保它也加入了订单和拖拉机信息,以便无需再次查找即可使用。
您可能不想更改后端的原因是它有点让数据变得不那么“纯粹”,因为现在您的端点正在同时返回多个模型的数据。 有时无论出于何种原因,您都无法更改后端。 您可能还决定此视图值得拥有自己的特殊端点。
另一个可能有效的解决方案是在前端获取所有拖拉机和订单信息的列表并将其存储,以便您可以查看缓存的信息,而不是每次都询问后端。 但缺点是您必须存储所有拖拉机和订单信息,这可能会很多。 如果您决定对后端结果进行“分页”,那么此解决方案将变得特别困难,但可能会奏效。
如果您确实决定使用“天真”方法 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.