Reputation: 977
Working with ReactJS, Redux and Firestore I get an error when creating a new record. However I do not understand the reason as I get the updated information correctly in Redux but after creating the record and returning to see all the records I get the error:
TypeError: Cannot read property 'name' of undefined
If I access to visualize the records everything is fine the problem is when I generate a new record and return to visualize all.
My jSON response is like:
1:
data: {email: "[email protected]", lastName: "Asdasd", name: "Oscar"}
uid: "2ts2DopIoXoiMVJ6lMKi"
When I back to get all the records and do a console.log(this.props.clients) return this:
0:DocumentReference
firestore:
Firestore {_queue: AsyncQueue, INTERNAL: {…}, _config: FirestoreConfig, _databaseId: DatabaseId, _dataConverter: UserDataConverter, …}
id:(...)
parent:(...)
path:(...)
_firestoreClient:FirestoreClient {platform: BrowserPlatform, databaseInfo: DatabaseInfo, credentials: FirebaseCredentialsProvider, asyncQueue: AsyncQueue, clientId: "BGuRUAvN7ZQxmmNEZmbx", …}
_key:DocumentKey {path: ResourcePath}
__proto__:Object
This is my code:
Action: Get data from Firestore
export const getFromFirestore= () => async dispatch => {
let res = [];
await db.collection('users').get().then((snapShot) => {
snapShot.docs.map( doc => {
res.push({ uid: doc.id, data: doc.data()});
})
}, error => {
console.log(error)
});
dispatch({
type: GET_CLIENTS,
payload:res
});
}
Reducer:
case GET_CLIENTS:
return{
...state,
clientsFirestore: action.payload
};
Clients Component Show data from Firestore:
class Clients extends Component {
componentDidMount(){
this.props.getFromFirestore();
};
deleteClient = (id) => {
this.props.deleteFirestore(id);
}
render() {
const { clients } = this.props;
return (
<React.Fragment>
<h1 className="display-4 mb-2">
<span className="text-danger">Clients</span>
</h1>
<table className="highlight centered">
<thead>
<tr>
<th>Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
{clients && clients !== undefined ? clients.map((client, key) => (
<Client
key={key}
id={client.uid}
name={client.data.name}
lastName={client.data.lastName}
email={client.data.email }
deleteClient={this.deleteClient}
/>
)): null }
</table>
</React.Fragment>
);
}
}
Clients.propTypes = {
clients: PropTypes.array.isRequired,
}
const mapStateToProps = (state) => ({
clients: state.clients.clientsFirestore
});
export default connect( mapStateToProps, { getFromFirestore, deleteFirestore } )(Clients);
Thanks!
Upvotes: 0
Views: 4631
Reputation: 977
Solution:
export const addToFirestore = (client) => async dispatch => {
let res ={
id:'',
data:{
name:'',
lastName:'',
email:''
}};
await db.collection("users").add({
name: client.name,
lastName: client.lastName,
email: client.email,
})
.then(function(docRef) {
res.id = docRef.id;
res.data.name = client.name;
res.data.lastName = client.lastName;
res.data.email = client.email;
})
.catch(function(error) {
console.error("Error adding document: ", error);
});
dispatch({
type: ADD_CLIENT,
payload:res
});
};
create an object since the answer of firestore only brings us the ID :|
Upvotes: 0
Reputation: 34014
You should also check whether the clients and client are undefined or not and only then do map and if you really have property called name
Check below code
{clients && clients != undefined ? clients.map((client, key) => (
{client && client != undefined && client.data && (<Client
key={key}
id={client.uid && client.uid }
name={client.data.name && client.data.name}
lastName={client.data.lastName && client.data.lastName}
email={client.data.email && client.data.email }
deleteClient={this.deleteClient}
/>)}
)): null }
PS:- When you post these type of questions try to post the json data as well to find resolution quickly
Upvotes: 1
Reputation: 905
Before returning, add an if query to check if the clients are fetched, then only map function will be able to use the inner object of client. Add a if (client === null) return <text>loading</text>
or something to avoid the fetching error which will return undefined for a nested object.
Edit : in mapStateToProps
define clients as
clients : this.state.clients
Upvotes: 0
Reputation: 4957
In Map function may be data property is undefined hence name property on data object throws TypeError: Cannot read property 'name' of undefined
Check data property has name property available before passing to <Client />
element.
<Client
key={key}
id={client.uid}
name={typeof client.data.name !== 'undefined' && client.data.name}
lastName={client.data.lastName}
email={client.data.email }
deleteClient={this.deleteClient}
/>
Upvotes: 0