【问题标题】:Is my console.log() supposed run 3 times?我的 console.log() 应该运行 3 次吗?
【发布时间】:2021-02-05 22:08:03
【问题描述】:

以下是我的组件页面之一的代码。就是将一些票据数据输入到 MongoDB 数据库中。我正在尝试通过在下拉框中选择客户名称来自行填充客户信息。我在第 18 行放了一个 console.log() ,只是为了看看我是否能弄清楚客户集合中的数据是在什么时候设置的。当我在第 18 行有 console.log() 时,它会出现 3 次。前两次它记录一个空数组,但第三次它有来自 MongoDB 的数据。我对编码很陌生,我有点困惑为什么 console.log 运行了 3 次。我对发布我的代码有点害羞,因为我仍然很清楚我确定我做错了各种各样的事情,但是有人可以在这方面引导我朝着正确的方向前进吗?它应该运行多次吗?此外,我收到以下警告,我无法弄清楚:

警告:列表中的每个孩子都应该有一个唯一的“key”属性。

Check the render method of `Tickets`. See https://reactjs.org/docs/lists-and-keys.html#keys for more information.
    in Fragment (created by Tickets)
    in Tickets (at App.js:22)
    in Route (at App.js:21)
    in Switch (at App.js:20)
    in div (at App.js:18)
    in Router (created by BrowserRouter)
    in BrowserRouter (at App.js:17)
    in App (at src/index.js:6)

我知道这与我在第 97 行的下拉选择有关,但我似乎无法弄清楚如何让它快乐。

import React, { useState, useEffect } from "react";
import DeleteBtn from "../DeleteBtn";
import Jumbotron from "../Jumbotron";
import API from "../../utils/API";
import { Link } from "react-router-dom";
import { Col, Row, Container } from "../Grid";
import { List, ListItem } from "../List";
import { Input, FormBtn } from "../Form";

const moment = require('moment');

function Tickets(props) {
  // Setting our component's initial state
  const [tickets, setTickets] = useState([])
  const [formObject, setFormObject] = useState({})
  const [customers, setCustomers] = useState([])

  console.log("Customer = ", customers)

  // Load all tickets and store them with setTickets
  useEffect(() => {
    loadTickets()
  }, [])

  // Loads all tickets and sets them to tickets
  function loadTickets() {
    API.getTickets()
      .then(res => 
        setTickets(res.data)
      )
      .catch(err => console.log(err));
  };  

  // Load all Customers and store them with setCustomer
  useEffect(() => {
    loadCustomers()
  }, [])

  // Loads all customers and sets them to customers
  function loadCustomers() {
    API.getCustomers()
    .then(res =>
      setCustomers(res.data)
    )
    .catch(err => console.log(err));
  };

  // Deletes a ticket from the database with a given id, then reloads tickets from the db
  function deleteTicket(id) {
    API.deleteTicket(id)
      .then(res => loadTickets())
      .catch(err => console.log(err));
  }

 // Handles updating component state when the user types into the input field
 function handleInputChange(event) {
   const { name, value } = event.target;
   setFormObject({...formObject, [name]: value})
 };

 // When the form is submitted, use the API.saveTicket method to save the ticket data
// Then reload tickets from the database
  function handleFormSubmit(event) {
    event.preventDefault();
    if (formObject.ticketDate) {
      API.saveTicket({
        ticketDate: formObject.ticketDate,
        ticketNum: formObject.ticketNum,
        ticketCust: formObject.ticketCust,
        ticketCustStreet: formObject.ticketCustStreet
      })
        .then(res => loadTickets())
        .catch(err => console.log(err));
        document.getElementById("ticketFrm").reset();  
        setFormObject({})      
    }
  };

  return (
    <Container fluid>
      <Row>
        <Col size="md-6">
          <Jumbotron>
            <h1>Add Ticket</h1>
          </Jumbotron>
          <form id="ticketFrm">
            <Input
              onChange={handleInputChange}
              name="ticketDate"
              placeholder="Date"
            />
            <Input
              onChange={handleInputChange}
              name="ticketNum"
              placeholder="Ticket Number (required)"
            />          
            <select onChange={handleInputChange}
              name="ticketCust"
              placeholder= "Customer Name"
              style={{width: '100%', height: 35, marginBottom: 15}}>
              {customers.map(customers => (
               <> 
               <option value="" hidden>Select Customer</option>
               <option default="Customer" key={customers._id}>{customers.custName}</option>  
              </>   
              ))}
            </select>
            <Input
              onChange={handleInputChange}
              name="ticketCustStreet"
              placeholder="Street"
            /> 
            <Input
              onChange={handleInputChange}
              name="ticketCustCity"
              placeholder="City"
            /> 
            <Input
              onChange={handleInputChange}
              name="ticketCustState"
              placeholder="State"
            /> 
            <Input
              onChange={handleInputChange}
              name="ticketCustZip"
              placeholder="Zip"
            /> 
            <Input
              onChange={handleInputChange}
              name="ticketCustMaterial"
              placeholder="Material"
            /> 
            <FormBtn
              disabled={!(formObject.ticketNum)}
              onClick={handleFormSubmit}>
              Submit Ticket
            </FormBtn>
          </form>
        </Col>
        <Col size="md-6 sm-12">
            <Jumbotron>
              <h1>Current Tickets</h1>
            </Jumbotron>
            {tickets.length ? (
              <List>
                {tickets.map(tickets => (
                  <ListItem key={tickets._id}>
                    <Link to={"/Tickets/" + tickets._id}>
                      <strong>
                      Ticket Date - {moment(tickets.ticketDate).format("MM-DD-YYYY")}
                        <br></br>
                      Ticket# - {tickets.ticketNum}
                      <br></br>
                      {tickets.ticketCust}
                      </strong>
                    </Link>
                    <DeleteBtn onClick={() => deleteTicket(tickets._id)}/>
                  </ListItem>
                ))}
              </List>
            ) : (
              <h3>No Results to Display</h3>
            )}
          </Col>
        </Row>
      </Container>
    );
}

export default Tickets;

感谢您的任何意见,请不要对我的代码过分苛责。

谢谢,

-N8

【问题讨论】:

    标签: javascript node.js reactjs mongodb mongoose


    【解决方案1】:

    您的useEffect 钩子在组件安装到DOM 后被调用。正在使用未定义的数据调用第一个控制台日志(因为尚未进行调用)

    关于Warning: Each child in a list should have a unique "key" prop.。键帮助 React 识别哪些项目已更改、添加或删除。应为数组内的元素提供键,以使元素具有稳定的标识。选择键的最佳方法是使用一个字符串,该字符串在其兄弟项中唯一标识一个列表项。大多数情况下,您会使用数据中的 ID 作为键。当渲染项目没有稳定的 ID 时,您可以使用项目索引作为键作为最后的手段。

    https://reactjs.org/docs/lists-and-keys.html

    所以要删除你的警告,我会做类似的事情

    {customers.map((customers, ii) => (
                   <> 
                   <option value="" key={ii} hidden>Select Customer</option>
                   <option default="Customer" key={customers._id}>{customers.custName}</option>  
                  </>   
                  ))}
    

    【讨论】:

    • 感谢您的反馈。我对此仍然有一点麻烦。我已将代码更改为您在此处列出的代码,但我仍然收到相同的警告。我已经阅读了关于 KEYS 的文档,但我认为让我失望的是我有
    【解决方案2】:

    首先,对某事不熟悉是可以的,我认为你不应该道歉。 最好的学习方法是提出问题、犯错误并让你的手“脏”,所以请随意:)。

    关于键问题,基本上,您从数组中渲染的每个元素都需要有一个唯一的键,因此当特定元素发生更改时,react 会知道。 因此,您的某些数据有可能与_id 保持一致。 例如,您可以在迭代中传递当前元素的索引(只需将索引参数添加到 map 函数),但我不会在您的情况下使用它,因为您的列表发生了变化,这是一种反模式。 有关密钥的更多信息,请阅读以下内容: React keys index as keys anti pattern

    关于多次出现的 console.log: 没关系,因为每次组件状态发生变化时,render 都会运行。 所以一开始你从空数组开始,当你的任何状态发生变化时,函数将运行并打印控制台日志。 我在反应渲染中找到了一个很好的指南,您可以深入了解: Complete Guide to React Rendering Behavior

    希望你会发现它有用!

    【讨论】:

      猜你喜欢
      • 2019-03-21
      • 2018-11-21
      • 1970-01-01
      • 2011-12-21
      • 2012-09-15
      • 1970-01-01
      • 2018-11-18
      • 2022-08-22
      • 2023-02-12
      相关资源
      最近更新 更多