OscarDev
OscarDev

Reputation: 977

ReactJS: TypeError: Cannot read property 'name' of undefined

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

Answers (4)

OscarDev
OscarDev

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

Hemadri Dasari
Hemadri Dasari

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

Sanchit Bhatnagar
Sanchit Bhatnagar

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

Sagar
Sagar

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

Related Questions