Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

153
Visualizações
react merging two components and sorting data by date and time (newest at top oldest and bottom)

I have codes below

code removed

The problem is it prints rows of expenses and then rows of incomes (i.e posts from expenses are printed first then after them incomes are printed). I need them to be mixed in and printed accordingly by date and time (newest post goes to top and oldest at bottom)

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

To minimize your code change, I'd propose to add another state called row and use componentDidUpdate to listen to expenses and incomes states change for row state update.

import axios from 'axios';
import React, { Component } from 'react'
import ExpenseRow from './ExpenseRow';
import IncomeRow from './IncomeRow';

class IncomeExpenseSummary extends Component {

    constructor(props) {
        super(props);
        this.state = {
            expenses:[],
            incomes:[],
            rows: []
        }
    }
   
    componentDidUpdate(prevProps, prevState) {
       //trigger when incomes or expenses change
       if(prevState.incomes !== this.state.incomes || prevState.expenses !== this.state.expenses) {
          //add type to recognize `income` in mixed list
          const updatedIncomes = [...this.state.incomes].map(income => ({...income, type: 'income'})) 
          //add type to recognize `expense` in mixed list
          const updatedExpenses = [...this.state.expenses].map(expense => ({...expense, type: 'expense'})) 
          //sort all rows with the mixed list
          const sortedRows = [...updatedExpenses, ...updatedIncomes].sort((a,b) => new Date(b.created_at) - new Date(a.created_at)) 
          this.setState({ rows: sortedRows })
       }
    }

    componentDidMount(){
        this.getExpenseList();
        this.getIncomeList();
    }

    getExpenseList = () =>{
        //if you use an arrow function, you don't need to pass variable for `this`
        axios.get('/get/expenses',{
            params:{_limit: 3}
        }).then((response) => {
            this.setState({
                expenses: response.data
            });
        });
    }

    getIncomeList =() =>{
        //if you use an arrow function, you don't need to pass variable for `this`
        axios.get('/get/incomes',{
            params:{_limit: 3}
        }).then((response) => {
            this.setState({
                incomes: response.data
            });
        });
    }

    render(){
        return(
            <div>
                <table className="table"> 
                {/* <toast/> */}
                <thead>
                    <tr>
                        <th scope="col">Date</th>
                        <th scope="col">Name</th>
                        <th scope="col">Price</th>
                        <th scope="col">Category</th>
                    </tr>
                </thead>
      <tbody>
            {this.state.rows.map((row) => row.type === 'expense' ? <ExpenseRow data={row} key={row.title}/> : <IncomeRow data={row} key={row.title}/>)}
      </tbody>
            </table>
            </div>
    );
    }
  }


export default IncomeExpenseSummary;
about 4 years ago · Juan Pablo Isaza Relatório

0

If you are aren't worried about rendering duplicate data, this should work for you. I simply merged the two states, sorted them by date, and passed that to your new combined component ExpenseIncomeRow. If you are actually trying to merge the data based on key/value properties, then this solution may not be ideal for you.

import axios from 'axios';
import React, { Component } from 'react'
import ExpenseIncomeRow from './ExpenseIncomeRow';

class IncomeExpenseSummary extends Component {

    constructor(props) {
        super(props);
        this.state = {
            expenses:[],
            incomes:[],
        }
    }

    componentDidMount(){
        this.getExpenseList();
        this.getIncomeList();
    }

    sortByDate = (data) => {
        data.sort((a, b) => new Date(b['created_at']) - new Date(a['created_at']))
    }

    getExpenseList =() =>{
        let self=this;
        axios.get('/get/expenses',{
            params:{_limit: 3}
        }).then(function(response)
            {self.setState({
                expenses: response.data
            });
        });
    }

    getIncomeList =() =>{
        let self=this;
        axios.get('/get/incomes',{
            params:{_limit: 3}
        }).then(function(response)
            {self.setState({
                incomes: response.data
            });
        });
    }


    render(){
        return(
            <div>
                <table className="table"> 
                {/* <toast/> */}
                <thead>
                    <tr>
                        <th scope="col">Date</th>
                        <th scope="col">Name</th>
                        <th scope="col">Price</th>
                        <th scope="col">Category</th>
                    </tr>
                </thead>
                <tbody>
                {this.sortByDate(this.state.expenses.slice(0, 4).concat(this.state.incomes.slice(0, 4)).map(function(x, i){
                    return <ExpenseIncomeRow key={i} data={x} />
                }))}
            </tbody>
            </table>
            </div>
        );
    }

}

export default IncomeExpenseSummary;

Here is the new component:

import React, { Component } from 'react'


class ExpenseIncomeRow extends Component {
    render(){
        return (
            <tr className='alert alert-success'>
                <th>{this.props.data.created_at}</th>
                <td>{this.props.data.title}</td>
                <td>{this.props.data.amount}</td>
                <td>{this.props.data.category}</td>
            </tr>
        )
    }
}
export default ExpenseIncomeRow;

I have changed your imports but you will actually have to set up a new component on your end for it to work properly.

about 4 years ago · Juan Pablo Isaza Relatório

0

I suggest adding a zip() helper:

// Zip array arguments together.
//
//     zip([1, 2, 3], [4, 5, 6])
//     //=> [[1, 4], [2, 5], [3, 6]]
//     zip([1], [2, 3], [])
//     //=> [[1, 2, undefined], [undefined, 3, undefined]]
//
function zip(...arrays) {
  if (!arrays.length) return [];
  const length = Math.max(...arrays.map(array => array.length));
  return Array.from({ length }, (_, i) => arrays.map(array => array[i]));
}

If you are already using a library with helper functions (Underscore.js, Lodash, Ramda, etc.), chances are that this function is available through it.

You can then use it within your JSX in the following manner:

// moved taking the first 3 elements up, to simplify the JSX
const take = (n, array) => array.slice(0, n + 1);
const expenses = take(3, this.state.expenses);
const incomes = take(3, this.state.incomes);

// ...

<tbody>
  {zip(expenses, incomes).map(([expense, income], i) => (
    <>
      <ExpenseRow key={i} data={expense} />
      <IncomeRow key={i} data={income} />
    </>
  ))}
</tbody>

This solution assumes the HTTP request returns the items in the correct order. If this isn't the case, you'll need to sort both the arrays first.


If the length of expenses and incomes can be different. Say expenses has length 1 and incomes has length 3. Then you'll probably want to add an additional check for both expenses and incomes (example only shows expenses).

{expense && <ExpenseRow key={i} data={expense} />}

Or you could return null in ExpenseRow if no data is provided.

class ExpenseRow extends Component {
    render() {
        if (!this.props.data) return null;
        // ...
    }
}
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda