【问题标题】:React.js - Having trouble creating a new invoice within my projectReact.js - 在我的项目中创建新发票时遇到问题
【发布时间】:2020-10-17 00:53:40
【问题描述】:

我是 React 的新手,并且可以真正用手来了解如何在我的项目中创建新发票。

问题: 目前,我可以创建一个新的发票没有问题,如下图所示。我将输入更改为一些测试数据以帮助说明我遇到的问题。

这是显示到目前为止堆栈中发票总数的俯视图。

当我去创建第二张新发票时出现问题。它保留了我修改的第一个数据中的所有旧数据,即使我可以单击它们并相互独立地修改它们。奇怪的是......只有一些值保持不变,而其他值可以相互独立......

这是在创建第二张发票后直接进行的:

我将第二张发票更改为所有新数据:

这是发票 1 中的结果:

现在,当我创建第三张新发票时:

这告诉我他们以某种方式连接.. 到我的项目的直接链接在这里:https://github.com/Brent-W-Anderson/invoice-pdf/tree/invoices

否则,我认为问题在于我如何创建新发票或如何修改其中的数据。请查看我修改发票的第 113 行或我正在创建新发票的第 94 行。我需要我能得到的所有帮助,谢谢!

https://github.com/Brent-W-Anderson/invoice-pdf/blob/invoices/src/components/app.js


import React from 'react';
import Moment from 'moment';

//components
import LoginSignUp from './login-signup/login-signup';
import Navigation from './navigation/navigation';
import Pages from './pages/pages';

//data
import UsersJSON from '../data/users.json'; // some test data for now. going to connect a database later.
import AppJSON from '../data/app.json';

//styling
import 'fontsource-roboto';
import '../styles/app.css';

export default class App extends React.Component {
  state = {
    loggedIn: false, // set to true to bypass logging in.
    transitionOut: false,
    activeUser: "", // can put whatever name you want here if loggedIn is set to true.
    activePage: "invoices",
    invoiceMode: "view", // dont change this unless you want to start with a specific manageable invoice.
    userData: {}, // set to the specific array index from the users if looking for some sample data.
    users: UsersJSON,
    appData: AppJSON
  };

  setActiveModeView = (clicked) => { // view all of the invoices
    this.setState({
      invoiceMode: "view"
    });
  }

  setActiveModeEdit = () => { // view a specific manageable/ editable invoice
    this.setState({
      invoiceMode: "edit"
    });
  }

  login = (userData) => { // login and store the users data for component use.
    let user = this;
    let username = userData.personalInfo.name;

    this.setState({
      userData: userData,
      transitionOut: false
    });

    setTimeout(function() { // let the app animate out before logging in.
      user.setState({
        loggedIn: true,
        activeUser: username
      });
    }, 1000);
  };

  logout = () => { // logout and reset the users data.
    let user = this;

    this.setState({
      transitionOut: true
    });

    setTimeout(function() { // let the app animate out before logging out.
      user.setState({
        loggedIn: false,
        userData: {},
        activePage: "invoices",
        invoiceMode: "view",
        activeUser: ""
      });
    }, 1500);
  }

  setActivePage = (page) => { // changing tabs
    let pageName = page.target.innerHTML.toLowerCase().replace(/\s/g, '');
    let app = this;

    if(pageName !== "invoices") { // change view mode back to defaults if not within invoices.
      setTimeout(function() {
        app.setActiveModeView();
      }, 500);
    }else {
      app.setActiveModeView("invoices");
    };

    this.setState({
      activePage: pageName
    });
  };


  createInvoice = idx => {
    console.log(UsersJSON[0].invoices[0]);

    this.setState(prevState => ({
      userData: {
        ...prevState.userData,
        invoices: [
          ...prevState.userData.invoices,
          {
            ...UsersJSON[0].invoices[0],
            invoiceID: idx + 1,
            date: Moment(new Date()).format("YYYY-MM-DD")
          }
        ]
      }
    }));
  };


  modifyInvoice = (userData, invoiceIdx, clientIdx, otherInputSelected, otherData) => (inputSelected) => { // editing specific invoice data and storing it back in state
    const app = this;
    let targetID, newVal;

    if(inputSelected !== undefined) {
      targetID = inputSelected.target.id;
      newVal = inputSelected.target.value;
    }else {
      switch(otherInputSelected) {
        case "billToEmail":
          targetID = otherInputSelected;
          newVal = otherData;
          break;

        case "fromEmail":
          targetID = otherInputSelected;
          newVal = otherData;
          break;

        default:
          console.warn("no other input selected to save to app state.");
      };
    }
    let newUserData = userData;

    function overwriteState() {
      app.setState({
        userData: newUserData
      });
    }

    switch(targetID) { // which input would you like to modify?
      case "invoiceName":
        newUserData.invoices[invoiceIdx].invoiceName = newVal;
        overwriteState();
        break;

      // BILL TO

      case "billToName":
        newUserData.invoices[invoiceIdx].toName = newVal;
        overwriteState();
        break;

      case "billToEmail":
        newUserData.invoices[invoiceIdx].toEmail = newVal;
        overwriteState();
        break;

      case "billToStreet":
        newUserData.invoices[invoiceIdx].toAddress.street = newVal;
        overwriteState();
        break;

      case "billToCityState":
        newUserData.invoices[invoiceIdx].toAddress.cityState = newVal;
        overwriteState();
        break;

      case "billToZip":
        newUserData.invoices[invoiceIdx].toAddress.zip = newVal;
        overwriteState();
        break;

      case "billToPhone":
        newUserData.invoices[invoiceIdx].toPhone = newVal;
        overwriteState();
        break;

      // FROM

      case "fromName":
        newUserData.invoices[invoiceIdx].fromName = newVal;
        overwriteState();
        break;

      case "fromEmail":
        newUserData.invoices[invoiceIdx].fromEmail = newVal;
        overwriteState();
        break;

      case "fromStreet":
        newUserData.invoices[invoiceIdx].fromAddress.street = newVal;
        overwriteState();
        break;

      case "fromCityState":
        newUserData.invoices[invoiceIdx].fromAddress.cityState = newVal;
        overwriteState();
        break;

      case "fromZip":
        newUserData.invoices[invoiceIdx].fromAddress.zip = newVal;
        overwriteState();
        break;

      case "fromPhone":
        newUserData.invoices[invoiceIdx].fromPhone = newVal;
        overwriteState();
        break;

      // DETAILS

      case "date":
        newUserData.invoices[invoiceIdx].date = newVal;
        overwriteState();
        break;

      case "description":
        newUserData.invoices[invoiceIdx].items.description = newVal;
        overwriteState();
        break;

      case "rate":
        newUserData.invoices[invoiceIdx].items.rate = newVal;
        overwriteState();
        break;

      case "qty":
        newUserData.invoices[invoiceIdx].items.qty = newVal;
        overwriteState();
        break;

      case "additionalDetails":
        newUserData.invoices[invoiceIdx].items.additionalDetails = newVal;
        overwriteState();
        break;

      default:
        console.warn("something went wrong... selected target input:");
        console.warn(targetID);
    }
  };


  deleteInvoice = (invoice, idx) => { // deletes an invoice
    let newUserData = this.state.userData;
    newUserData.invoices.splice(idx, 1);

    for(var x = 0; x < newUserData.invoices.length; x++) {
      newUserData.invoices[x].invoiceID = (x + 1).toString();
    }

    this.setState({
      userData: newUserData
    });
  }


  render() {
    let app = this.state;

    if(app.loggedIn) { // if logged in
      return (
        <div className="app">
          <Navigation
            activeUser={app.activeUser}
            setActivePage={this.setActivePage}
            activePage={app.activePage}
            appData={app.appData}
            logout={this.logout}
          />
          <Pages
            setActiveModeView={this.setActiveModeView}
            setActiveModeEdit={this.setActiveModeEdit}
            invoiceMode={app.invoiceMode}
            activePage={app.activePage}
            appData={app.appData}
            transitionOut={app.transitionOut}
            userData={app.userData}
            createInvoice={this.createInvoice}
            modifyInvoice={this.modifyInvoice}
            deleteInvoice={this.deleteInvoice}
          />
        </div>
      );
    }else { // if not logged in
      return (
        <div className="app">
          <LoginSignUp
            login={this.login}
            users={app.users}
          />
        </div>
      );
    }
  }
}

【问题讨论】:

    标签: javascript reactjs react-state


    【解决方案1】:

    我相信一种选择是改变:

          case "billToStreet":
            newUserData.invoices[invoiceIdx].toAddress.street = newVal;
            overwriteState();
            break;
    

    到:

          case "billToStreet":
            newUserData.invoices[invoiceIdx].toAddress = { ...newUserData.invoices[invoiceIdx].toAddress, street: newVal };
            overwriteState();
            break;
    

    并对其他地址字段执行相同操作。

    我不知道为什么,但我怀疑你所有的 toAddress 条目都引用了同一个对象。

    【讨论】:

    • 哇,谢谢,这实际上解决了问题。为什么这可以解决问题?它不是仍然以相同的方式分配值只是不同的语法吗?我似乎无法让这个解决方案适用于我的任何订单项,包括详细信息、费率、数量等。
    • 我怀疑问题的根源在于 createInvoice() 函数。 ...UsersJSON[0].invoices[0] 将从该来源复制 toAddress 和 fromAddress - 除非它不是副本 - 当您创建两个这样的发票时,我认为两者都可能引用相同的 toAddress 在UsersJSON[0].invoices[0].toAddress 并将更新该对象。我认为我提供的代码有效,因为它为 toAddress 创建了一个新对象,而不是仅仅更新被引用的对象,但解决这个问题的更好地方可能是在 createInvoice() 函数中。
    • 好的,经过大量的窥探和谷歌的反复试验,我找到了解决方案。扩展运算符 {} 在其变异状态方面存在问题。我在这里找到了它:stackoverflow.com/questions/47624142/… 通过简单地改变我获取模板的方式,它完全解决了我的问题。再次感谢您的帮助,您为我指明了正确的方向,我的朋友 =)
    猜你喜欢
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    相关资源
    最近更新 更多