Reputation: 841
I created a reactJS app that has a main page and a details page, the main page get data from a database that has a alpha numeric unique key, once i click the details page and render the details component but when i go back to the main page Warning : Encountered two children with the same key
is encountered.
This key is from a firebase database.
My App.js
function App() {
return (
<div className="App">
<Router>
<Navbar />
<Route path="/" exact component={ExpenseList} />
<Route path="/details/:id" component={ExpenseDetails} />
</Router>
</div>
);
}
My main page component the tran variable is set as a global variable
import React, {Component} from 'react';
import { Link, useHistory } from 'react-router-dom';
import {db} from '../server';
let tran = [];
componentDidMount(){
db.collection('transactions').orderBy('added_at', 'desc').onSnapshot(snapshot => {
let changes = snapshot.docChanges();
changes.forEach(change => {
if(change.type == 'added'){
tran.push(change.doc);
}
});
this.setState( {transactions: tran});
});
}
displayTransactions(){
return this.state.transactions.map(transaction => {
return <Transaction record={transaction.data()} key={transaction.id} sequence={transaction.id} />;
})
}
render(){
return(
<div className="container mt-4">
<h2>Transaction List</h2>
<div className="mt-5" id="renderTransactions">
{this.displayTransactions()}
</div>
</div>
)
}
My details page
componentDidMount(){
var docID = this.props.match.params.id;
db.collection('transactions').doc(docID).get().then( doc => {
let details = {
_id: doc.id,
title: doc.data().title,
details: doc.data().details,
category: doc.data().category,
dateTransaction: doc.data().dateTransaction,
amount: doc.data().amount,
transType: doc.data().transType,
}
this.setState( {transactionDetails: details});
});
}
transactionDetails(){
return <TransactionDetails record={this.state.transactionDetails} deleteTransaction={this.deleteTransaction} />;
}
render(){
return(
<div className="mt-5">
<div className="container">
<h2 className="mb-5">Transaction Details</h2>
{this.transactionDetails()}
</div>
</div>
)
}
Upvotes: 1
Views: 217
Reputation: 203471
Ok, so it seems you are mutating state, indirectly. tran
caches all previously fetched db data.
let tran = [];
componentDidMount(){
db.collection('transactions').orderBy('added_at', 'desc').onSnapshot(snapshot => {
let changes = snapshot.docChanges();
changes.forEach(change => {
if(change.type == 'added'){
tran.push(change.doc);
}
});
this.setState({ transactions: tran });
});
}
tran
appears to be locally global, and each time the component mounts it pushes all the changes into tran
and then sets state. Each time the component mounts, it again pushes all the changes into tran
and sets state. These subsequent mountings use the existing populated tran
array and possibly pushes in duplicate data.
I suspect you meant for each mount to be "fresh". For this I suggest mapping the changes
to your state. Since the "same data elements will be returned including the new added data" you can simply consume the entire array, there is no need to keep "state" outside the component and no need to filter by the "added" elements.
componentDidMount(){
db.collection('transactions').orderBy('added_at', 'desc').onSnapshot(snapshot => {
const changes = snapshot.docChanges();
this.setState({ transactions: changes });
});
}
Upvotes: 1