简体   繁体   English

如何按 ObjectId 过滤并计算 react.js 中的总成本

[英]how to filter by ObjectId and calculate total cost in react.js

The table is rendered twice for Wade Ivan.该表为 Wade Ivan 渲染了两次。 Instead, the table should be rendered only once.相反,表格应该只呈现一次。 The total should be 180 and not 680.总数应该是 180 而不是 680。

I have a search class component.我有一个搜索 class 组件。 However, when i search for clients by their names based on ObjectId(clientdetails._id), rendering returns multiple tables equivalent to the number of documents with that ObjectId.Moreover, the total bill calculated gives the total cost from all objectIds instead of the total cost derived from documents with similar ObjectId (clientdetails._id)但是,当我根据 ObjectId(clientdetails._id) 按名称搜索客户时,渲染返回多个表,等于具有该 ObjectId 的文档数。此外,计算的总账单给出了所有 objectIds 的总成本而不是总成本从具有相似 ObjectId (clientdetails._id) 的文档派生的成本

import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";

const isSearched = searchTerm => item => {
  if (searchTerm === "") {
    return;
  }
  return item.clientdetails.fullName.toLowerCase().includes(searchTerm.toLowerCase());
};

export default class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      list:[
        {
          "_id": "6389d19a3b28b9e4af3694f8",
          "clientdetails": {
            "_id": "6389d1193b28b9e4af3694f2",
            "fullName": "WADE IVAN",
            "dateofBirth": "1990-01-01T00:00:00.000Z",
            "age": 32,
            "__v": 0
          },
          "paymentReferenceCode": "1",
          "paymentType": "Cash",
          "paymentDescription": "ACCOMODATION",
          "procedureAmount": "100",
          "paymentDiscount": 20,
          "AmountPaid": 100,
          "Total": 100,
          "__v": 0
        },
        {
          "_id": "6389d1bb3b28b9e4af369500",
          "clientdetails": {
            "_id": "6389d1193b28b9e4af3694f2",
            "fullName": "WADE IVAN",
            "dateofBirth": "1990-01-01T00:00:00.000Z",
            "age": 32,
            "__v": 0
          },
          "paymentReferenceCode": "12",
          "paymentType": "Cash",
          "paymentDescription": "ACCOMODATION",
          "procedureAmount": "100",
          "paymentDiscount": 20,
          "AmountPaid": 80,
          "Total": 80,
          "__v": 0
        },
        {
          "_id": "6389d1e03b28b9e4af369508",
          "clientdetails": {
            "_id": "6389d0ed3b28b9e4af3694ee",
            "fullName": "JOHN MARK",
            "dateofBirth": "2000-01-12T00:00:00.000Z",
            "age": 22,
            "__v": 0
          },
          "paymentReferenceCode": "3",
          "paymentType": "Cash",
          "paymentDescription": "100",
          "procedureAmount": "100",
          "paymentDiscount": 20,
          "AmountPaid": 200,
          "Total": 200,
          "__v": 0
        },
        {
          "_id": "6389d2173b28b9e4af369510",
          "clientdetails": {
            "_id": "6389d0ed3b28b9e4af3694ee",
            "fullName": "JOHN MARK",
            "dateofBirth": "2000-01-12T00:00:00.000Z",
            "age": 22,
            "__v": 0
          },
          "paymentReferenceCode": "9",
          "paymentType": "Cash",
          "paymentDescription": "ACCOMODATION",
          "procedureAmount": "10",
          "paymentDiscount": 2,
          "AmountPaid": 300,
          "Total": 300,
          "__v": 0
        }
      ],
      searchTerm: ""
    };
  }

  onSearchChange = event => {
    this.setState({ searchTerm: event.target.value });
  };

  render() {
    const { searchTerm, list } = this.state;
    
    return (
      <div className="page">
        <div className="interactions">
          <Search 
            value={searchTerm} 
            SearchChange={this.onSearchChange}
          >
            Search
          </Search>
          <Table list={list} pattern={searchTerm} onDismiss={this.onDismiss} />
        </div>
      </div>
    );
  }
}
const Search = ({ value, SearchChange, children }) => {
  return (
    <form>
      {children}
      <input type="text" value={value} onChange={SearchChange} />
    </form>
  )
}


class Table extends React.Component {
  render() {
    const { list, pattern } = this.props;
    const total=(list.reduce((total,item) =>  total = total + item.AmountPaid , 0 ));
    return (
      <div className="table">
        {list.filter(isSearched(pattern)).map(item => (
          <div key={item.clientdetails.fullName} className="table-row" >
<table>
                <thead>
                <tr>
                    <th>Client Name </th>
                    <th>Payment Reference Code</th>
                    <th>Payment Type</th>
                    <th>Payment Description</th>
                    <th>Procedure Amount</th>
                    <th>Payment Discount </th>
                    <th>Amount Paid </th>
                    
                </tr>
            </thead>
            <tbody>
            {list.filter(isSearched(pattern)).map(item => (
                    <tr > 
                        <td>{item.clientdetails.fullName}</td>

                        <td>{item.paymentReferenceCode}</td>
                        <td>{item.paymentType}</td>
                        <td>{item.paymentDescription}</td>
                        <td>{item.procedureAmount}</td>
                        <td>{item.paymentDiscount}</td>
                        <td>{item.AmountPaid}</td>
                       
                       
                    </tr>
                    ))}
                   <tfoot><tr>
                        Total: 
                             {total}
                           </tr>  
                    </tfoot>
            </tbody>
        </table>
          </div>
        ))}
      </div>
    );
  } 
}

How can i improve this code.我该如何改进这段代码。 Thanks in advance提前致谢

Here is the basic solution这是基本的解决方案

let items = [
  {
    _id: "6389d19a3b28b9e4af3694f8",
    clientdetails: {
      _id: "6389d1193b28b9e4af3694f2",
      fullName: "WADE IVAN",
      dateofBirth: "1990-01-01T00:00:00.000Z",
      age: 32,
      __v: 0
    },
    paymentReferenceCode: "1",
    paymentType: "Cash",
    paymentDescription: "ACCOMODATION",
    procedureAmount: "100",
    paymentDiscount: 20,
    AmountPaid: 100,
    Total: 100,
    __v: 0
  },
  {
    _id: "6389d1bb3b28b9e4af369500",
    clientdetails: {
      _id: "6389d1193b28b9e4af3694f2",
      fullName: "WADE IVAN",
      dateofBirth: "1990-01-01T00:00:00.000Z",
      age: 32,
      __v: 0
    },
    paymentReferenceCode: "12",
    paymentType: "Cash",
    paymentDescription: "ACCOMODATION",
    procedureAmount: "100",
    paymentDiscount: 20,
    AmountPaid: 80,
    Total: 80,
    __v: 0
  },
  {
    _id: "6389d1e03b28b9e4af369508",
    clientdetails: {
      _id: "6389d0ed3b28b9e4af3694ee",
      fullName: "JOHN MARK",
      dateofBirth: "2000-01-12T00:00:00.000Z",
      age: 22,
      __v: 0
    },
    paymentReferenceCode: "3",
    paymentType: "Cash",
    paymentDescription: "100",
    procedureAmount: "100",
    paymentDiscount: 20,
    AmountPaid: 200,
    Total: 200,
    __v: 0
  },
  {
    _id: "6389d2173b28b9e4af369510",
    clientdetails: {
      _id: "6389d0ed3b28b9e4af3694ee",
      fullName: "JOHN MARK",
      dateofBirth: "2000-01-12T00:00:00.000Z",
      age: 22,
      __v: 0
    },
    paymentReferenceCode: "9",
    paymentType: "Cash",
    paymentDescription: "ACCOMODATION",
    procedureAmount: "10",
    paymentDiscount: 2,
    AmountPaid: 300,
    Total: 300,
    __v: 0
  }
];

const reduced = items.reduce((acc, curr) => {
  //console.log(curr);
  const prop = curr.clientdetails._id;
 const existingTotal = acc?.[prop]?.total ?? 0;
  return {
    ...acc,
    [prop]: {
      id: prop,
      name: curr.clientdetails.fullName,
      total: existingTotal + curr.Total
    }
  };
}, {});

const list = Object.entries(reduced).map(([key, value]) => {
  return {
    id: key,
    name: value.name,
    total: value.total
  };
});

console.log("reduced", reduced);
console.log("list", list);

To include it in component将其包含在组件中

// if only final total is needed, this function can be optimized
// if grouping is needed then total needs to be gropued for each entry
function getTotal(items) {
  try {

      const reduced = items?.reduce((acc, curr) => {
      const prop = curr.clientdetails._id;
      const existingTotal = acc?.[prop]?.total ?? 0;
    
      console.log(acc, acc?.[prop]);
      console.log(acc, curr.clientdetails.fullName);
    
      return {
        ...acc,
        [prop]: {
          id: prop,
          name: curr.clientdetails.fullName,
          total: existingTotal + curr.Total
        }
      };
    }, {});

    const total = Object.entries(reduced).reduce((acc, [key, value]) => {
     
      return acc + value.total 
     
    }, 0);

    return total;
    
  } catch (error) {
    console.log("error", error);
    return 0;
  }
}

// for grouping filtered items
function groupItems(items) {
  try {
    const grouped = items?.reduce((acc, curr) => {
      const prop = curr.clientdetails._id;
      //const id = curr.clientdetails._id;

      const existingTotal = acc?.[prop]?.total ?? 0;

      let entries = acc[prop]?.entries ?? [];

      entries.push({
        id: curr._id,
        total: curr.Total,
        paymentType: curr.paymentType
        // include more props
      });

      return {
        ...acc,
        [prop]: {
          name: curr.clientdetails.fullName,
          total: existingTotal + curr.Total,
          entries
        }
      };
    }, {});

    console.log("list", grouped);

    const list = Object.entries(grouped).map(([key, value]) => {
      return {
        id: key,
        name: value.name,
        total: value.total,
        entries: value.entries
      };
    });

    return list;
  } catch (error) {
    console.log("error", error);
    return [];
  }
}

/*
will contain list of
{
    id: key,
    name: value.name,
    total: value.total,
    // contains individual entries and the total for the grouped entries
    entries: [
      {
         id: curr._id,
         total: curr.Total,
         paymentType: curr.paymentType
      }
    ]

}
*/

class Table extends React.Component {

  render() {

    const { list, pattern } = this.props;

    const filteredList = list.filter(isSearched(pattern));

    const grouped = groupItems(filteredList);
   /*
    will contain list of
   {
    id: key,
    name: value.name,
    total: value.total,
    // contains individual entries and the total for the grouped entries
    entries: [
      {
         id: curr._id,
         total: curr.Total,
         paymentType: curr.paymentType
      }
    ]

    }
   */
    // TODO
    // you can write function to get total from grouped items

    const total = getTotal(filteredList)

    return (
      <div className="table">
        //you can show the gropued entries here
        {grouped?.map(({ id, total: grpTotal, entries = [] }) => (
          <div key={item.id} className="table-row" >

This code an be optimized for performance and made simpler with functional components.此代码针对性能进行了优化,并通过功能组件变得更简单。

Hope it helps希望能帮助到你

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

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