1

I am getting the user data from an api using the fetch() function. In the render function I want to pass the props using the ...userdata but it gives me error when I create object before return statement. The error is : TypeError: Cannot read property 'id' of undefined

Error is because at the time of loading the application there is no userData, its fetched only on search button click.

Please let me know how can I create the object and pass it as prop, instead of passing each member of object separately as prop. i.e.

import React from 'react';
import './App.css';
import SearchBar from "./components/search";
import Result from "./components/result";

class ContactSearch extends React.Component {
  constructor() {
    super();
    this.state = {
      // userData: {
        // id: 0,
        // name: "",
        // username: ""
      // },
      userData : [],
      userAddr : {},
      searchDone: false,
      errorMessage: ""
    };

    this.callUserData = this.callUserData.bind(this);
  }

  callUserData(user) {
    const url = `<URL>`;

    fetch(url)
      .then(handleErrors)
      .then(resp => resp.json())
      .then(data => {
        var { ...addr} = data[0].address;
        this.setState({
          userData: [...data],
          userAddr: addr,
          searchDone: true,
          errorMessage: ""
        });
      })
      .catch(error => {
        // If an error is catch, it's sent to SearchBar as props
        this.setState({ errorMessage: error.message });
      });

    function handleErrors(response) {
      if (!response.ok) {
        throw Error(response.statusText);
      }
      return response;
    }
  }

  render() {
    const { searchDone, userData, userAddr, errorMessage } = this.state;
    console.log('Inside render');

        let **user** = {
                id : userData[0].id,
                name:userData[0].name,
                email:userData[0].email,
                address:userAddr
            };

        return (
          <div className="ContactSearch">
            <SearchBar
              callBackFromParent={this.callUserData}
              error={errorMessage}
            />

            {searchDone && userData && (
              <Result

                    {...**user**}
              />
            )}
          </div>
        );
  }
}

export default ContactSearch;
Ismael Padilla
  • 5,246
  • 4
  • 23
  • 35
  • Does this answer your question? [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) – Emile Bergeron Jan 03 '20 at 00:32
  • The problem is that `userData[0]` is `undefined` while the `fetch` is ongoing. You need to account for that in the render logic. – Emile Bergeron Jan 03 '20 at 00:34
  • Do you need something like this` `? – Alex Jan 03 '20 at 02:03
  • @Alex, you are correct. – Mahesh Verma Jan 03 '20 at 02:27
  • Does this answer your question? [How to render data in react getting undefined state?](https://stackoverflow.com/questions/54204066/how-to-render-data-in-react-getting-undefined-state) – Dan O Jan 03 '20 at 02:33

2 Answers2

0

You can use an if statement to check whether or not the data you need was loaded into the state already, so as to avoid trying to access it on the first render:

const { searchDone, userData, userAddr, errorMessage } = this.state;
let user = null;
if (userData.length > 0) {
    user = {
        id : userData[0].id,
        name:userData[0].name,
        email:userData[0].email,
        address:userAddr
    };
}

A shorter way to do the same thing:

const { searchDone, userData, userAddr, errorMessage } = this.state;
let user = searchDone && {
    id : userData[0].id,
    name:userData[0].name,
    email:userData[0].email,
    address:userAddr
};
Ismael Padilla
  • 5,246
  • 4
  • 23
  • 35
  • your first solution gives same error again. TypeError: Cannot read property 'id' of undefined userData is not null but just an empty array. Second one works fine. Thanks. – Mahesh Verma Jan 03 '20 at 02:23
  • You're right, I missed that you're initializing `userData` as an empty array, sorry! I've edited my answer – Ismael Padilla Jan 03 '20 at 02:26
  • I did the same :-) i.e. if (userData.length > 0) ..... Thanks. – Mahesh Verma Jan 03 '20 at 03:19
  • That's great to hear, you're welcome, @Mahesh! If this or any answer has solved your question please consider upvoting it and accepting it by clicking the check-mark. This indicates to the wider community that you've found a solution and gives some reputation to both the answerer and yourself. There is no obligation to do this. Cheers! – Ismael Padilla Jan 03 '20 at 03:21
0

Maybe you need this

<Result user={searchDone && userData[0]} />

Result component could be like this

const Result=(props)=>
 ( props.user?<div>{props.user.id}</div>:'no result..^.^')

if your data is like [{id:1},{id:2}] remove extra Bracket from data userData: [data]

should be like below

      userData: data,

temporary sandbox example

Alex
  • 3,941
  • 1
  • 17
  • 24