tengo codigos abajo
code removedEl problema es que imprime filas de gastos y luego filas de ingresos (es decir, las publicaciones de gastos se imprimen primero y luego se imprimen los ingresos). Necesito que se mezclen e impriman según la fecha y la hora (la publicación más reciente va arriba y la más antigua abajo)
Para minimizar su cambio de código, propondría agregar otro estado llamado row y usar componentDidUpdate para escuchar los cambios en los estados de expenses e incomes para la actualización del estado de la row .
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;Si no le preocupa generar datos duplicados, esto debería funcionar para usted. Simplemente fusioné los dos estados, los clasifiqué por fecha y lo pasé a su nuevo componente combinado ExpenseIncomeRow . Si realmente está tratando de fusionar los datos en función de las propiedades de key/value , es posible que esta solución no sea ideal para usted.
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;Aquí está el nuevo componente:
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; Cambié sus imports , pero en realidad tendrá que configurar un nuevo componente para que funcione correctamente.
Sugiero agregar un ayudante zip() :
// 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])); }Si ya está utilizando una biblioteca con funciones auxiliares (Underscore.js, Lodash, Ramda, etc.), es probable que esta función esté disponible a través de ella.
Luego puede usarlo dentro de su JSX de la siguiente manera:
// 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>Esta solución asume que la solicitud HTTP devuelve los elementos en el orden correcto. Si este no es el caso, primero deberá ordenar ambas matrices.
Si la duración de los expenses y incomes pueden ser diferentes. Digamos que expenses tienen una longitud 1 y incomes tienen una longitud 3 . Entonces, probablemente desee agregar un cheque adicional tanto para los expenses como para los incomes (el ejemplo solo muestra expenses ).
{expense && <ExpenseRow key={i} data={expense} />} O podría devolver null en ExpenseRow si no se proporcionan datos.
class ExpenseRow extends Component { render() { if (!this.props.data) return null; // ... } }